Merge pull request #26614 from vahagsaribekyan/master
Add dependencyOf property to Component catalog model
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/catalog-model': minor
|
||||
'@backstage/plugin-catalog-backend': minor
|
||||
---
|
||||
|
||||
Add `dependencyOf` prop to catalog model for Component kind to enable building relationship graphs with both directions using `dependsOn` and `dependencyOf`.
|
||||
@@ -527,6 +527,8 @@ spec:
|
||||
system: artist-engagement-portal
|
||||
dependsOn:
|
||||
- resource:default/artists-db
|
||||
dependencyOf:
|
||||
- component:default/artist-web-lookup
|
||||
providesApis:
|
||||
- artist-api
|
||||
```
|
||||
@@ -636,6 +638,17 @@ field is optional.
|
||||
| [`Component`](#kind-component) | Same as this entity, typically `default` | [`dependsOn`, and reverse `dependencyOf`](well-known-relations.md#dependson-and-dependencyof) |
|
||||
| [`Resource`](#kind-resource) | Same as this entity, typically `default` | [`dependsOn`, and reverse `dependencyOf`](well-known-relations.md#dependson-and-dependencyof) |
|
||||
|
||||
### `spec.dependencyOf` [optional]
|
||||
|
||||
An array of [entity references](references.md#string-references) to the
|
||||
components and resources that the component is a dependency of, e.g. `artist-web-lookup`.
|
||||
This field is optional.
|
||||
|
||||
| [`kind`](#apiversion-and-kind-required) | Default [`namespace`](#namespace-optional) | Generated [relation](well-known-relations.md) type |
|
||||
| --------------------------------------- | ------------------------------------------ | --------------------------------------------------------------------------------------------- |
|
||||
| [`Component`](#kind-component) | Same as this entity, typically `default` | [`dependencyOf`, and reverse `dependsOn`](well-known-relations.md#dependson-and-dependencyof) |
|
||||
| [`Resource`](#kind-resource) | Same as this entity, typically `default` | [`dependencyOf`, and reverse `dependsOn`](well-known-relations.md#dependson-and-dependencyof) |
|
||||
|
||||
## Kind: Template
|
||||
|
||||
The following describes the following entity kind:
|
||||
|
||||
@@ -87,6 +87,7 @@ interface ComponentEntityV1alpha1 extends Entity {
|
||||
providesApis?: string[];
|
||||
consumesApis?: string[];
|
||||
dependsOn?: string[];
|
||||
dependencyOf?: string[];
|
||||
system?: string;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ export interface ComponentEntityV1alpha1 extends Entity {
|
||||
providesApis?: string[];
|
||||
consumesApis?: string[];
|
||||
dependsOn?: string[];
|
||||
dependencyOf?: string[];
|
||||
system?: string;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -46,13 +46,14 @@ describe('BuiltinKindsEntityProcessor', () => {
|
||||
providesApis: ['b'],
|
||||
consumesApis: ['c'],
|
||||
dependsOn: ['Resource:r', 'Component:d'],
|
||||
dependencyOf: ['Resource:f', 'Component:g'],
|
||||
system: 's',
|
||||
},
|
||||
};
|
||||
|
||||
await processor.postProcessEntity(entity, location, emit);
|
||||
|
||||
expect(emit).toHaveBeenCalledTimes(14);
|
||||
expect(emit).toHaveBeenCalledTimes(18);
|
||||
expect(emit).toHaveBeenCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
@@ -133,6 +134,38 @@ describe('BuiltinKindsEntityProcessor', () => {
|
||||
target: { kind: 'Component', namespace: 'default', name: 'n' },
|
||||
},
|
||||
});
|
||||
expect(emit).toHaveBeenCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
source: { kind: 'Component', namespace: 'default', name: 'n' },
|
||||
type: 'dependencyOf',
|
||||
target: { kind: 'Resource', namespace: 'default', name: 'f' },
|
||||
},
|
||||
});
|
||||
expect(emit).toHaveBeenCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
source: { kind: 'Resource', namespace: 'default', name: 'f' },
|
||||
type: 'dependsOn',
|
||||
target: { kind: 'Component', namespace: 'default', name: 'n' },
|
||||
},
|
||||
});
|
||||
expect(emit).toHaveBeenCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
source: { kind: 'Component', namespace: 'default', name: 'n' },
|
||||
type: 'dependencyOf',
|
||||
target: { kind: 'Component', namespace: 'default', name: 'g' },
|
||||
},
|
||||
});
|
||||
expect(emit).toHaveBeenCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
source: { kind: 'Component', namespace: 'default', name: 'g' },
|
||||
type: 'dependsOn',
|
||||
target: { kind: 'Component', namespace: 'default', name: 'n' },
|
||||
},
|
||||
});
|
||||
expect(emit).toHaveBeenCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
@@ -190,6 +223,29 @@ describe('BuiltinKindsEntityProcessor', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('generates an error for component entities with unspecified dependencyOf entity reference kinds', async () => {
|
||||
const entity: ComponentEntity = {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'Component',
|
||||
metadata: { name: 'n' },
|
||||
spec: {
|
||||
type: 'service',
|
||||
owner: 'o',
|
||||
subcomponentOf: 's',
|
||||
lifecycle: 'l',
|
||||
providesApis: ['b'],
|
||||
consumesApis: ['c'],
|
||||
dependencyOf: ['y'],
|
||||
system: 's',
|
||||
},
|
||||
};
|
||||
await expect(
|
||||
processor.postProcessEntity(entity, location, emit),
|
||||
).rejects.toThrow(
|
||||
'Entity reference "y" had missing or empty kind (e.g. did not start with "component:" or similar)',
|
||||
);
|
||||
});
|
||||
|
||||
it('generates relations for api entities', async () => {
|
||||
const entity: ApiEntity = {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
|
||||
@@ -166,6 +166,12 @@ export class BuiltinKindsEntityProcessor implements CatalogProcessor {
|
||||
RELATION_DEPENDS_ON,
|
||||
RELATION_DEPENDENCY_OF,
|
||||
);
|
||||
doEmit(
|
||||
component.spec.dependencyOf,
|
||||
{ defaultNamespace: selfRef.namespace },
|
||||
RELATION_DEPENDENCY_OF,
|
||||
RELATION_DEPENDS_ON,
|
||||
);
|
||||
doEmit(
|
||||
component.spec.system,
|
||||
{ defaultKind: 'System', defaultNamespace: selfRef.namespace },
|
||||
|
||||
Reference in New Issue
Block a user