@backstage/plugin-catalog-backend 1.7.0-next.0 → 1.7.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 +43 -0
- package/alpha/package.json +1 -1
- package/dist/index.cjs.js +225 -12
- package/dist/index.cjs.js.map +1 -1
- package/package.json +18 -18
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,48 @@
|
|
|
1
1
|
# @backstage/plugin-catalog-backend
|
|
2
2
|
|
|
3
|
+
## 1.7.0-next.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- e23f13a573: Enable the `by-refs` endpoint to receive `fields` through the POST body as well as through query parameters.
|
|
8
|
+
- f23eef3aa2: Updated dependency `better-sqlite3` to `^8.0.0`.
|
|
9
|
+
- 8e06f3cf00: Switched imports of `loggerToWinstonLogger` to `@backstage/backend-common`.
|
|
10
|
+
- Updated dependencies
|
|
11
|
+
- @backstage/backend-plugin-api@0.3.0-next.1
|
|
12
|
+
- @backstage/backend-common@0.18.0-next.1
|
|
13
|
+
- @backstage/catalog-client@1.3.0-next.2
|
|
14
|
+
- @backstage/plugin-catalog-node@1.3.1-next.2
|
|
15
|
+
- @backstage/plugin-permission-node@0.7.3-next.1
|
|
16
|
+
- @backstage/catalog-model@1.1.5-next.1
|
|
17
|
+
- @backstage/config@1.0.6-next.0
|
|
18
|
+
- @backstage/errors@1.1.4
|
|
19
|
+
- @backstage/integration@1.4.2-next.0
|
|
20
|
+
- @backstage/types@1.0.2
|
|
21
|
+
- @backstage/plugin-catalog-common@1.0.10-next.1
|
|
22
|
+
- @backstage/plugin-permission-common@0.7.3-next.0
|
|
23
|
+
- @backstage/plugin-scaffolder-common@1.2.4-next.1
|
|
24
|
+
- @backstage/plugin-search-common@1.2.1-next.0
|
|
25
|
+
|
|
26
|
+
## 1.7.0-next.1
|
|
27
|
+
|
|
28
|
+
### Patch Changes
|
|
29
|
+
|
|
30
|
+
- Updated dependencies
|
|
31
|
+
- @backstage/backend-plugin-api@0.2.1-next.0
|
|
32
|
+
- @backstage/backend-common@0.18.0-next.0
|
|
33
|
+
- @backstage/config@1.0.6-next.0
|
|
34
|
+
- @backstage/plugin-catalog-node@1.3.1-next.1
|
|
35
|
+
- @backstage/catalog-client@1.3.0-next.1
|
|
36
|
+
- @backstage/catalog-model@1.1.5-next.1
|
|
37
|
+
- @backstage/errors@1.1.4
|
|
38
|
+
- @backstage/integration@1.4.2-next.0
|
|
39
|
+
- @backstage/types@1.0.2
|
|
40
|
+
- @backstage/plugin-catalog-common@1.0.10-next.1
|
|
41
|
+
- @backstage/plugin-permission-common@0.7.3-next.0
|
|
42
|
+
- @backstage/plugin-permission-node@0.7.3-next.0
|
|
43
|
+
- @backstage/plugin-scaffolder-common@1.2.4-next.1
|
|
44
|
+
- @backstage/plugin-search-common@1.2.1-next.0
|
|
45
|
+
|
|
3
46
|
## 1.7.0-next.0
|
|
4
47
|
|
|
5
48
|
### Minor Changes
|
package/alpha/package.json
CHANGED
package/dist/index.cjs.js
CHANGED
|
@@ -97,8 +97,11 @@ function normalizeCodeOwner(owner) {
|
|
|
97
97
|
|
|
98
98
|
const CODEOWNERS = "CODEOWNERS";
|
|
99
99
|
const scmCodeOwnersPaths = {
|
|
100
|
+
// https://mibexsoftware.atlassian.net/wiki/spaces/CODEOWNERS/pages/222822413/Usage
|
|
100
101
|
bitbucket: [CODEOWNERS, `.bitbucket/${CODEOWNERS}`],
|
|
102
|
+
// https://docs.gitlab.com/ee/user/project/code_owners.html#how-to-set-up-code-owners
|
|
101
103
|
gitlab: [CODEOWNERS, `.gitlab/${CODEOWNERS}`, `docs/${CODEOWNERS}`],
|
|
104
|
+
// https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-file-location
|
|
102
105
|
github: [CODEOWNERS, `.github/${CODEOWNERS}`, `docs/${CODEOWNERS}`]
|
|
103
106
|
};
|
|
104
107
|
|
|
@@ -1549,6 +1552,9 @@ async function updateUnprocessedEntity(options) {
|
|
|
1549
1552
|
unprocessed_hash: hash,
|
|
1550
1553
|
location_key: locationKey,
|
|
1551
1554
|
last_discovery_at: tx.fn.now(),
|
|
1555
|
+
// We only get to this point if a processed entity actually had any changes, or
|
|
1556
|
+
// if an entity provider requested this mutation, meaning that we can safely
|
|
1557
|
+
// bump the deferred entities to the front of the queue for immediate processing.
|
|
1552
1558
|
next_update_at: tx.fn.now()
|
|
1553
1559
|
}).where("entity_ref", entityRef).andWhere((inner) => {
|
|
1554
1560
|
if (!locationKey) {
|
|
@@ -1707,6 +1713,7 @@ class DefaultProcessingDatabase {
|
|
|
1707
1713
|
result = await fn(tx);
|
|
1708
1714
|
},
|
|
1709
1715
|
{
|
|
1716
|
+
// If we explicitly trigger a rollback, don't fail.
|
|
1710
1717
|
doNotRejectOnRollback: true
|
|
1711
1718
|
}
|
|
1712
1719
|
);
|
|
@@ -1722,6 +1729,10 @@ class DefaultProcessingDatabase {
|
|
|
1722
1729
|
(r) => `${r.source_entity_ref}:${r.target_entity_ref}:${r.type}`
|
|
1723
1730
|
);
|
|
1724
1731
|
}
|
|
1732
|
+
/**
|
|
1733
|
+
* Add a set of deferred entities for processing.
|
|
1734
|
+
* The entities will be added at the front of the processing queue.
|
|
1735
|
+
*/
|
|
1725
1736
|
async addUnprocessedEntities(txOpaque, options) {
|
|
1726
1737
|
const tx = txOpaque;
|
|
1727
1738
|
const stateReferences = new Array();
|
|
@@ -2159,6 +2170,7 @@ class DefaultLocationService {
|
|
|
2159
2170
|
const processed = await this.orchestrator.process({
|
|
2160
2171
|
entity: currentEntity.entity,
|
|
2161
2172
|
state: {}
|
|
2173
|
+
// we process without the existing cache
|
|
2162
2174
|
});
|
|
2163
2175
|
if (processed.ok) {
|
|
2164
2176
|
if (entities.some(
|
|
@@ -2749,6 +2761,8 @@ class DefaultCatalogProcessingOrchestrator {
|
|
|
2749
2761
|
};
|
|
2750
2762
|
}
|
|
2751
2763
|
}
|
|
2764
|
+
// Pre-process phase, used to populate entities with data that is required
|
|
2765
|
+
// during the main processing step
|
|
2752
2766
|
async runPreProcessStep(entity, context) {
|
|
2753
2767
|
let res = entity;
|
|
2754
2768
|
for (const processor of this.options.processors) {
|
|
@@ -2771,6 +2785,9 @@ class DefaultCatalogProcessingOrchestrator {
|
|
|
2771
2785
|
}
|
|
2772
2786
|
return res;
|
|
2773
2787
|
}
|
|
2788
|
+
/**
|
|
2789
|
+
* Enforce entity policies making sure that entities conform to a general schema
|
|
2790
|
+
*/
|
|
2774
2791
|
async runPolicyStep(entity) {
|
|
2775
2792
|
let policyEnforcedEntity;
|
|
2776
2793
|
try {
|
|
@@ -2790,6 +2807,9 @@ class DefaultCatalogProcessingOrchestrator {
|
|
|
2790
2807
|
}
|
|
2791
2808
|
return policyEnforcedEntity;
|
|
2792
2809
|
}
|
|
2810
|
+
/**
|
|
2811
|
+
* Validate the given entity
|
|
2812
|
+
*/
|
|
2793
2813
|
async runValidateStep(entity, context) {
|
|
2794
2814
|
if (catalogModel.stringifyEntityRef(entity) !== context.entityRef) {
|
|
2795
2815
|
throw new errors.ConflictError(
|
|
@@ -2829,6 +2849,9 @@ class DefaultCatalogProcessingOrchestrator {
|
|
|
2829
2849
|
);
|
|
2830
2850
|
}
|
|
2831
2851
|
}
|
|
2852
|
+
/**
|
|
2853
|
+
* Backwards compatible processing of location entities
|
|
2854
|
+
*/
|
|
2832
2855
|
async runSpecialLocationStep(entity, context) {
|
|
2833
2856
|
const { type = context.location.type, presence = "required" } = entity.spec;
|
|
2834
2857
|
const targets = new Array();
|
|
@@ -2888,6 +2911,9 @@ class DefaultCatalogProcessingOrchestrator {
|
|
|
2888
2911
|
}
|
|
2889
2912
|
}
|
|
2890
2913
|
}
|
|
2914
|
+
/**
|
|
2915
|
+
* Main processing step of the entity
|
|
2916
|
+
*/
|
|
2891
2917
|
async runPostProcessStep(entity, context) {
|
|
2892
2918
|
let res = entity;
|
|
2893
2919
|
for (const processor of this.options.processors) {
|
|
@@ -3108,7 +3134,10 @@ class Stitcher {
|
|
|
3108
3134
|
}));
|
|
3109
3135
|
}
|
|
3110
3136
|
}
|
|
3111
|
-
entity.relations = relationsResult.filter(
|
|
3137
|
+
entity.relations = relationsResult.filter(
|
|
3138
|
+
(row) => row.relationType
|
|
3139
|
+
/* exclude null row, if relevant */
|
|
3140
|
+
).map((row) => ({
|
|
3112
3141
|
type: row.relationType,
|
|
3113
3142
|
targetRef: row.relationTarget
|
|
3114
3143
|
}));
|
|
@@ -3147,7 +3176,8 @@ class Stitcher {
|
|
|
3147
3176
|
}
|
|
3148
3177
|
|
|
3149
3178
|
const schema = zod.z.object({
|
|
3150
|
-
entityRefs: zod.z.array(zod.z.string())
|
|
3179
|
+
entityRefs: zod.z.array(zod.z.string()),
|
|
3180
|
+
fields: zod.z.array(zod.z.string()).optional()
|
|
3151
3181
|
});
|
|
3152
3182
|
function entitiesBatchRequest(req) {
|
|
3153
3183
|
try {
|
|
@@ -3274,17 +3304,22 @@ function getPathArrayAndValue(input, field) {
|
|
|
3274
3304
|
[[], input]
|
|
3275
3305
|
);
|
|
3276
3306
|
}
|
|
3277
|
-
function parseEntityTransformParams(params) {
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3307
|
+
function parseEntityTransformParams(params, extra) {
|
|
3308
|
+
var _a;
|
|
3309
|
+
const queryFields = parseStringsParam(params.fields, "fields");
|
|
3310
|
+
const fields = Array.from(
|
|
3311
|
+
new Set(
|
|
3312
|
+
[...extra != null ? extra : [], ...(_a = queryFields == null ? void 0 : queryFields.map((s) => s.split(","))) != null ? _a : []].flat().map((s) => s.trim()).filter(Boolean)
|
|
3313
|
+
)
|
|
3314
|
+
);
|
|
3283
3315
|
if (!fields.length) {
|
|
3284
3316
|
return void 0;
|
|
3285
3317
|
}
|
|
3286
|
-
|
|
3287
|
-
|
|
3318
|
+
const arrayTypeField = fields.find((f) => f.includes("["));
|
|
3319
|
+
if (arrayTypeField) {
|
|
3320
|
+
throw new errors.InputError(
|
|
3321
|
+
`Invalid field "${arrayTypeField}", array type fields are not supported`
|
|
3322
|
+
);
|
|
3288
3323
|
}
|
|
3289
3324
|
return (input) => {
|
|
3290
3325
|
const output = {};
|
|
@@ -3454,7 +3489,7 @@ async function createRouter(options) {
|
|
|
3454
3489
|
const token = getBearerToken(req.header("authorization"));
|
|
3455
3490
|
const response = await entitiesCatalog.entitiesBatch({
|
|
3456
3491
|
entityRefs: request.entityRefs,
|
|
3457
|
-
fields: parseEntityTransformParams(req.query),
|
|
3492
|
+
fields: parseEntityTransformParams(req.query, request.fields),
|
|
3458
3493
|
authorizationToken: token
|
|
3459
3494
|
});
|
|
3460
3495
|
res.status(200).json(response);
|
|
@@ -3618,6 +3653,44 @@ const _DefaultCatalogRulesEnforcer = class {
|
|
|
3618
3653
|
constructor(rules) {
|
|
3619
3654
|
this.rules = rules;
|
|
3620
3655
|
}
|
|
3656
|
+
/**
|
|
3657
|
+
* Loads catalog rules from config.
|
|
3658
|
+
*
|
|
3659
|
+
* This reads `catalog.rules` and defaults to the default rules if no value is present.
|
|
3660
|
+
* The value of the config should be a list of config objects, each with a single `allow`
|
|
3661
|
+
* field which in turn is a list of entity kinds to allow.
|
|
3662
|
+
*
|
|
3663
|
+
* If there is no matching rule to allow an ingested entity, it will be rejected by the catalog.
|
|
3664
|
+
*
|
|
3665
|
+
* It also reads in rules from `catalog.locations`, where each location can have a list
|
|
3666
|
+
* of rules for that specific location, specified in a `rules` field.
|
|
3667
|
+
*
|
|
3668
|
+
* For example:
|
|
3669
|
+
*
|
|
3670
|
+
* ```yaml
|
|
3671
|
+
* catalog:
|
|
3672
|
+
* rules:
|
|
3673
|
+
* - allow: [Component, API]
|
|
3674
|
+
* - allow: [Template]
|
|
3675
|
+
* locations:
|
|
3676
|
+
* - type: url
|
|
3677
|
+
* pattern: https://github.com/org/*\/blob/master/template.yaml
|
|
3678
|
+
* - allow: [Location]
|
|
3679
|
+
* locations:
|
|
3680
|
+
* - type: url
|
|
3681
|
+
* pattern: https://github.com/org/repo/blob/master/location.yaml
|
|
3682
|
+
*
|
|
3683
|
+
* locations:
|
|
3684
|
+
* - type: url
|
|
3685
|
+
* target: https://github.com/org/repo/blob/master/users.yaml
|
|
3686
|
+
* rules:
|
|
3687
|
+
* - allow: [User, Group]
|
|
3688
|
+
* - type: url
|
|
3689
|
+
* target: https://github.com/org/repo/blob/master/systems.yaml
|
|
3690
|
+
* rules:
|
|
3691
|
+
* - allow: [System]
|
|
3692
|
+
* ```
|
|
3693
|
+
*/
|
|
3621
3694
|
static fromConfig(config) {
|
|
3622
3695
|
const rules = new Array();
|
|
3623
3696
|
if (config.has("catalog.rules")) {
|
|
@@ -3660,6 +3733,10 @@ const _DefaultCatalogRulesEnforcer = class {
|
|
|
3660
3733
|
}
|
|
3661
3734
|
return new _DefaultCatalogRulesEnforcer(rules);
|
|
3662
3735
|
}
|
|
3736
|
+
/**
|
|
3737
|
+
* Checks whether a specific entity/location combination is allowed
|
|
3738
|
+
* according to the configured rules.
|
|
3739
|
+
*/
|
|
3663
3740
|
isAllowed(entity, location) {
|
|
3664
3741
|
for (const rule of this.rules) {
|
|
3665
3742
|
if (!this.matchLocation(location, rule.locations)) {
|
|
@@ -3704,6 +3781,11 @@ const _DefaultCatalogRulesEnforcer = class {
|
|
|
3704
3781
|
}
|
|
3705
3782
|
};
|
|
3706
3783
|
let DefaultCatalogRulesEnforcer = _DefaultCatalogRulesEnforcer;
|
|
3784
|
+
/**
|
|
3785
|
+
* Default rules used by the catalog.
|
|
3786
|
+
*
|
|
3787
|
+
* Denies any location from specifying user or group entities.
|
|
3788
|
+
*/
|
|
3707
3789
|
DefaultCatalogRulesEnforcer.defaultRules = [
|
|
3708
3790
|
{
|
|
3709
3791
|
allow: ["Component", "API", "Location"].map((kind) => ({ kind }))
|
|
@@ -4052,6 +4134,7 @@ class DefaultProviderDatabase {
|
|
|
4052
4134
|
result = await fn(tx);
|
|
4053
4135
|
},
|
|
4054
4136
|
{
|
|
4137
|
+
// If we explicitly trigger a rollback, don't fail.
|
|
4055
4138
|
doNotRejectOnRollback: true
|
|
4056
4139
|
}
|
|
4057
4140
|
);
|
|
@@ -4233,6 +4316,7 @@ class DefaultCatalogDatabase {
|
|
|
4233
4316
|
result = await fn(tx);
|
|
4234
4317
|
},
|
|
4235
4318
|
{
|
|
4319
|
+
// If we explicitly trigger a rollback, don't fail.
|
|
4236
4320
|
doNotRejectOnRollback: true
|
|
4237
4321
|
}
|
|
4238
4322
|
);
|
|
@@ -4302,13 +4386,33 @@ class CatalogBuilder {
|
|
|
4302
4386
|
this.permissionRules = Object.values(permissionRules);
|
|
4303
4387
|
this.allowedLocationType = ["url"];
|
|
4304
4388
|
}
|
|
4389
|
+
/**
|
|
4390
|
+
* Creates a catalog builder.
|
|
4391
|
+
*/
|
|
4305
4392
|
static create(env) {
|
|
4306
4393
|
return new CatalogBuilder(env);
|
|
4307
4394
|
}
|
|
4395
|
+
/**
|
|
4396
|
+
* Adds policies that are used to validate entities between the pre-
|
|
4397
|
+
* processing and post-processing stages. All such policies must pass for the
|
|
4398
|
+
* entity to be considered valid.
|
|
4399
|
+
*
|
|
4400
|
+
* If what you want to do is to replace the rules for what format is allowed
|
|
4401
|
+
* in various core entity fields (such as metadata.name), you may want to use
|
|
4402
|
+
* {@link CatalogBuilder#setFieldFormatValidators} instead.
|
|
4403
|
+
*
|
|
4404
|
+
* @param policies - One or more policies
|
|
4405
|
+
*/
|
|
4308
4406
|
addEntityPolicy(...policies) {
|
|
4309
4407
|
this.entityPolicies.push(...policies.flat());
|
|
4310
4408
|
return this;
|
|
4311
4409
|
}
|
|
4410
|
+
/**
|
|
4411
|
+
* Processing interval determines how often entities should be processed.
|
|
4412
|
+
* Seconds provided will be multiplied by 1.5
|
|
4413
|
+
* The default processing interval is 100-150 seconds.
|
|
4414
|
+
* setting this too low will potentially deplete request quotas to upstream services.
|
|
4415
|
+
*/
|
|
4312
4416
|
setProcessingIntervalSeconds(seconds) {
|
|
4313
4417
|
this.processingInterval = createRandomProcessingInterval({
|
|
4314
4418
|
minSeconds: seconds,
|
|
@@ -4316,40 +4420,109 @@ class CatalogBuilder {
|
|
|
4316
4420
|
});
|
|
4317
4421
|
return this;
|
|
4318
4422
|
}
|
|
4423
|
+
/**
|
|
4424
|
+
* Overwrites the default processing interval function used to spread
|
|
4425
|
+
* entity updates in the catalog.
|
|
4426
|
+
*/
|
|
4319
4427
|
setProcessingInterval(processingInterval) {
|
|
4320
4428
|
this.processingInterval = processingInterval;
|
|
4321
4429
|
return this;
|
|
4322
4430
|
}
|
|
4431
|
+
/**
|
|
4432
|
+
* Overwrites the default location analyzer.
|
|
4433
|
+
*/
|
|
4323
4434
|
setLocationAnalyzer(locationAnalyzer) {
|
|
4324
4435
|
this.locationAnalyzer = locationAnalyzer;
|
|
4325
4436
|
return this;
|
|
4326
4437
|
}
|
|
4438
|
+
/**
|
|
4439
|
+
* Sets what policies to use for validation of entities between the pre-
|
|
4440
|
+
* processing and post-processing stages. All such policies must pass for the
|
|
4441
|
+
* entity to be considered valid.
|
|
4442
|
+
*
|
|
4443
|
+
* If what you want to do is to replace the rules for what format is allowed
|
|
4444
|
+
* in various core entity fields (such as metadata.name), you may want to use
|
|
4445
|
+
* {@link CatalogBuilder#setFieldFormatValidators} instead.
|
|
4446
|
+
*
|
|
4447
|
+
* This function replaces the default set of policies; use with care.
|
|
4448
|
+
*
|
|
4449
|
+
* @param policies - One or more policies
|
|
4450
|
+
*/
|
|
4327
4451
|
replaceEntityPolicies(policies) {
|
|
4328
4452
|
this.entityPolicies = [...policies];
|
|
4329
4453
|
this.entityPoliciesReplace = true;
|
|
4330
4454
|
return this;
|
|
4331
4455
|
}
|
|
4456
|
+
/**
|
|
4457
|
+
* Adds, or overwrites, a handler for placeholders (e.g. $file) in entity
|
|
4458
|
+
* definition files.
|
|
4459
|
+
*
|
|
4460
|
+
* @param key - The key that identifies the placeholder, e.g. "file"
|
|
4461
|
+
* @param resolver - The resolver that gets values for this placeholder
|
|
4462
|
+
*/
|
|
4332
4463
|
setPlaceholderResolver(key, resolver) {
|
|
4333
4464
|
this.placeholderResolvers[key] = resolver;
|
|
4334
4465
|
return this;
|
|
4335
4466
|
}
|
|
4467
|
+
/**
|
|
4468
|
+
* Sets the validator function to use for one or more special fields of an
|
|
4469
|
+
* entity. This is useful if the default rules for formatting of fields are
|
|
4470
|
+
* not sufficient.
|
|
4471
|
+
*
|
|
4472
|
+
* This function has no effect if used together with
|
|
4473
|
+
* {@link CatalogBuilder#replaceEntityPolicies}.
|
|
4474
|
+
*
|
|
4475
|
+
* @param validators - The (subset of) validators to set
|
|
4476
|
+
*/
|
|
4336
4477
|
setFieldFormatValidators(validators) {
|
|
4337
4478
|
lodash__default["default"].merge(this.fieldFormatValidators, validators);
|
|
4338
4479
|
return this;
|
|
4339
4480
|
}
|
|
4481
|
+
/**
|
|
4482
|
+
* Adds or replaces entity providers. These are responsible for bootstrapping
|
|
4483
|
+
* the list of entities out of original data sources. For example, there is
|
|
4484
|
+
* one entity source for the config locations, and one for the database
|
|
4485
|
+
* stored locations. If you ingest entities out of a third party system, you
|
|
4486
|
+
* may want to implement that in terms of an entity provider as well.
|
|
4487
|
+
*
|
|
4488
|
+
* @param providers - One or more entity providers
|
|
4489
|
+
*/
|
|
4340
4490
|
addEntityProvider(...providers) {
|
|
4341
4491
|
this.entityProviders.push(...providers.flat());
|
|
4342
4492
|
return this;
|
|
4343
4493
|
}
|
|
4494
|
+
/**
|
|
4495
|
+
* Adds entity processors. These are responsible for reading, parsing, and
|
|
4496
|
+
* processing entities before they are persisted in the catalog.
|
|
4497
|
+
*
|
|
4498
|
+
* @param processors - One or more processors
|
|
4499
|
+
*/
|
|
4344
4500
|
addProcessor(...processors) {
|
|
4345
4501
|
this.processors.push(...processors.flat());
|
|
4346
4502
|
return this;
|
|
4347
4503
|
}
|
|
4504
|
+
/**
|
|
4505
|
+
* Sets what entity processors to use. These are responsible for reading,
|
|
4506
|
+
* parsing, and processing entities before they are persisted in the catalog.
|
|
4507
|
+
*
|
|
4508
|
+
* This function replaces the default set of processors, consider using with
|
|
4509
|
+
* {@link CatalogBuilder#getDefaultProcessors}; use with care.
|
|
4510
|
+
*
|
|
4511
|
+
* @param processors - One or more processors
|
|
4512
|
+
*/
|
|
4348
4513
|
replaceProcessors(processors) {
|
|
4349
4514
|
this.processors = [...processors];
|
|
4350
4515
|
this.processorsReplace = true;
|
|
4351
4516
|
return this;
|
|
4352
4517
|
}
|
|
4518
|
+
/**
|
|
4519
|
+
* Returns the default list of entity processors. These are responsible for reading,
|
|
4520
|
+
* parsing, and processing entities before they are persisted in the catalog. Changing
|
|
4521
|
+
* the order of processing can give more control to custom processors.
|
|
4522
|
+
*
|
|
4523
|
+
* Consider using with {@link CatalogBuilder#replaceProcessors}
|
|
4524
|
+
*
|
|
4525
|
+
*/
|
|
4353
4526
|
getDefaultProcessors() {
|
|
4354
4527
|
const { config, logger, reader } = this.env;
|
|
4355
4528
|
const integrations = integration.ScmIntegrations.fromConfig(config);
|
|
@@ -4360,26 +4533,63 @@ class CatalogBuilder {
|
|
|
4360
4533
|
new AnnotateLocationEntityProcessor({ integrations })
|
|
4361
4534
|
];
|
|
4362
4535
|
}
|
|
4536
|
+
/**
|
|
4537
|
+
* Adds Location Analyzers. These are responsible for analyzing
|
|
4538
|
+
* repositories when onboarding them into the catalog, by finding
|
|
4539
|
+
* catalog-info.yaml files and other artifacts that can help automatically
|
|
4540
|
+
* register or create catalog data on the user's behalf.
|
|
4541
|
+
*
|
|
4542
|
+
* @param locationAnalyzers - One or more location analyzers
|
|
4543
|
+
*/
|
|
4363
4544
|
addLocationAnalyzers(...analyzers) {
|
|
4364
4545
|
this.locationAnalyzers.push(...analyzers.flat());
|
|
4365
4546
|
return this;
|
|
4366
4547
|
}
|
|
4548
|
+
/**
|
|
4549
|
+
* Sets up the catalog to use a custom parser for entity data.
|
|
4550
|
+
*
|
|
4551
|
+
* This is the function that gets called immediately after some raw entity
|
|
4552
|
+
* specification data has been read from a remote source, and needs to be
|
|
4553
|
+
* parsed and emitted as structured data.
|
|
4554
|
+
*
|
|
4555
|
+
* @param parser - The custom parser
|
|
4556
|
+
*/
|
|
4367
4557
|
setEntityDataParser(parser) {
|
|
4368
4558
|
this.parser = parser;
|
|
4369
4559
|
return this;
|
|
4370
4560
|
}
|
|
4561
|
+
/**
|
|
4562
|
+
* Adds additional permission rules. Permission rules are used to evaluate
|
|
4563
|
+
* catalog resources against queries. See
|
|
4564
|
+
* {@link @backstage/plugin-permission-node#PermissionRule}.
|
|
4565
|
+
*
|
|
4566
|
+
* @param permissionRules - Additional permission rules
|
|
4567
|
+
* @alpha
|
|
4568
|
+
*/
|
|
4371
4569
|
addPermissionRules(...permissionRules) {
|
|
4372
4570
|
this.permissionRules.push(...permissionRules.flat());
|
|
4373
4571
|
return this;
|
|
4374
4572
|
}
|
|
4573
|
+
/**
|
|
4574
|
+
* Sets up the allowed location types from being registered via the location service.
|
|
4575
|
+
*
|
|
4576
|
+
* @param allowedLocationTypes - the allowed location types
|
|
4577
|
+
*/
|
|
4375
4578
|
setAllowedLocationTypes(allowedLocationTypes) {
|
|
4376
4579
|
this.allowedLocationType = allowedLocationTypes;
|
|
4377
4580
|
return this;
|
|
4378
4581
|
}
|
|
4582
|
+
/**
|
|
4583
|
+
* Enables the legacy behaviour of canceling validation early whenever only a
|
|
4584
|
+
* single processor declares an entity kind to be valid.
|
|
4585
|
+
*/
|
|
4379
4586
|
useLegacySingleProcessorValidation() {
|
|
4380
4587
|
this.legacySingleProcessorValidation = true;
|
|
4381
4588
|
return this;
|
|
4382
4589
|
}
|
|
4590
|
+
/**
|
|
4591
|
+
* Wires up and returns all of the component parts of the catalog
|
|
4592
|
+
*/
|
|
4383
4593
|
async build() {
|
|
4384
4594
|
var _a, _b;
|
|
4385
4595
|
const { config, database, logger, permissions } = this.env;
|
|
@@ -4542,6 +4752,8 @@ class CatalogBuilder {
|
|
|
4542
4752
|
this.checkMissingExternalProcessors(processors);
|
|
4543
4753
|
return processors;
|
|
4544
4754
|
}
|
|
4755
|
+
// TODO(Rugvip): These old processors are removed, for a while we'll be throwing
|
|
4756
|
+
// errors here to make sure people know where to move the config
|
|
4545
4757
|
checkDeprecatedReaderProcessors() {
|
|
4546
4758
|
const pc = this.env.config.getOptionalConfig("catalog.processors");
|
|
4547
4759
|
if (pc == null ? void 0 : pc.has("github")) {
|
|
@@ -4565,6 +4777,7 @@ class CatalogBuilder {
|
|
|
4565
4777
|
);
|
|
4566
4778
|
}
|
|
4567
4779
|
}
|
|
4780
|
+
// TODO(freben): This can be removed no sooner than June 2022, after adopters have had some time to adapt to the new package structure
|
|
4568
4781
|
checkMissingExternalProcessors(processors) {
|
|
4569
4782
|
var _a, _b;
|
|
4570
4783
|
const skipCheckVarName = "BACKSTAGE_CATALOG_SKIP_MISSING_PROCESSORS_CHECK";
|
|
@@ -4699,7 +4912,7 @@ const catalogPlugin = backendPluginApi.createBackendPlugin({
|
|
|
4699
4912
|
httpRouter,
|
|
4700
4913
|
lifecycle
|
|
4701
4914
|
}) {
|
|
4702
|
-
const winstonLogger =
|
|
4915
|
+
const winstonLogger = backendCommon.loggerToWinstonLogger(logger);
|
|
4703
4916
|
const builder = await CatalogBuilder.create({
|
|
4704
4917
|
config,
|
|
4705
4918
|
reader,
|