Merge pull request #26614 from vahagsaribekyan/master

Add dependencyOf property to Component catalog model
This commit is contained in:
Johan Haals
2024-09-16 13:20:01 +02:00
committed by GitHub
6 changed files with 84 additions and 1 deletions
+6
View File
@@ -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:
+1
View File
@@ -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 },