Merge pull request #5150 from jmgrimes/dependsOn-dependencyOf-relationships
Implemented dependsOn/dependencyOf support in catalog model.
This commit is contained in:
+113
-2
@@ -45,13 +45,14 @@ describe('BuiltinKindsEntityProcessor', () => {
|
||||
lifecycle: 'l',
|
||||
providesApis: ['b'],
|
||||
consumesApis: ['c'],
|
||||
dependsOn: ['Resource:r', 'Component:d'],
|
||||
system: 's',
|
||||
},
|
||||
};
|
||||
|
||||
await processor.postProcessEntity(entity, location, emit);
|
||||
|
||||
expect(emit).toBeCalledTimes(10);
|
||||
expect(emit).toBeCalledTimes(14);
|
||||
expect(emit).toBeCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
@@ -100,6 +101,38 @@ describe('BuiltinKindsEntityProcessor', () => {
|
||||
target: { kind: 'API', namespace: 'default', name: 'c' },
|
||||
},
|
||||
});
|
||||
expect(emit).toBeCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
source: { kind: 'Component', namespace: 'default', name: 'n' },
|
||||
type: 'dependsOn',
|
||||
target: { kind: 'Resource', namespace: 'default', name: 'r' },
|
||||
},
|
||||
});
|
||||
expect(emit).toBeCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
source: { kind: 'Resource', namespace: 'default', name: 'r' },
|
||||
type: 'dependencyOf',
|
||||
target: { kind: 'Component', namespace: 'default', name: 'n' },
|
||||
},
|
||||
});
|
||||
expect(emit).toBeCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
source: { kind: 'Component', namespace: 'default', name: 'n' },
|
||||
type: 'dependsOn',
|
||||
target: { kind: 'Component', namespace: 'default', name: 'd' },
|
||||
},
|
||||
});
|
||||
expect(emit).toBeCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
source: { kind: 'Component', namespace: 'default', name: 'd' },
|
||||
type: 'dependencyOf',
|
||||
target: { kind: 'Component', namespace: 'default', name: 'n' },
|
||||
},
|
||||
});
|
||||
expect(emit).toBeCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
@@ -134,6 +167,29 @@ describe('BuiltinKindsEntityProcessor', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('generates an error for component entities with unspecified dependsOn 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'],
|
||||
dependsOn: ['r'],
|
||||
system: 's',
|
||||
},
|
||||
};
|
||||
await expect(
|
||||
processor.postProcessEntity(entity, location, emit),
|
||||
).rejects.toThrowError(
|
||||
'Entity reference "r" did not specify a kind (e.g. starting with "Component:"), and has no default',
|
||||
);
|
||||
});
|
||||
|
||||
it('generates relations for api entities', async () => {
|
||||
const entity: ApiEntity = {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
@@ -193,13 +249,14 @@ describe('BuiltinKindsEntityProcessor', () => {
|
||||
spec: {
|
||||
type: 'database',
|
||||
owner: 'o',
|
||||
dependsOn: ['Component:c', 'Resource:r'],
|
||||
system: 's',
|
||||
},
|
||||
};
|
||||
|
||||
await processor.postProcessEntity(entity, location, emit);
|
||||
|
||||
expect(emit).toBeCalledTimes(4);
|
||||
expect(emit).toBeCalledTimes(8);
|
||||
expect(emit).toBeCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
@@ -216,6 +273,41 @@ describe('BuiltinKindsEntityProcessor', () => {
|
||||
target: { kind: 'Group', namespace: 'default', name: 'o' },
|
||||
},
|
||||
});
|
||||
|
||||
expect(emit).toBeCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
source: { kind: 'Resource', namespace: 'default', name: 'n' },
|
||||
type: 'dependsOn',
|
||||
target: { kind: 'Component', namespace: 'default', name: 'c' },
|
||||
},
|
||||
});
|
||||
expect(emit).toBeCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
source: { kind: 'Component', namespace: 'default', name: 'c' },
|
||||
type: 'dependencyOf',
|
||||
target: { kind: 'Resource', namespace: 'default', name: 'n' },
|
||||
},
|
||||
});
|
||||
|
||||
expect(emit).toBeCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
source: { kind: 'Resource', namespace: 'default', name: 'n' },
|
||||
type: 'dependsOn',
|
||||
target: { kind: 'Resource', namespace: 'default', name: 'r' },
|
||||
},
|
||||
});
|
||||
expect(emit).toBeCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
source: { kind: 'Resource', namespace: 'default', name: 'r' },
|
||||
type: 'dependencyOf',
|
||||
target: { kind: 'Resource', namespace: 'default', name: 'n' },
|
||||
},
|
||||
});
|
||||
|
||||
expect(emit).toBeCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
@@ -234,6 +326,25 @@ describe('BuiltinKindsEntityProcessor', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('generates an error for resource entities with unspecified dependsOn entity reference kinds', async () => {
|
||||
const entity: ResourceEntity = {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'Resource',
|
||||
metadata: { name: 'n' },
|
||||
spec: {
|
||||
type: 'database',
|
||||
owner: 'o',
|
||||
dependsOn: ['c'],
|
||||
system: 's',
|
||||
},
|
||||
};
|
||||
await expect(
|
||||
processor.postProcessEntity(entity, location, emit),
|
||||
).rejects.toThrowError(
|
||||
'Entity reference "c" did not specify a kind (e.g. starting with "Component:"), and has no default',
|
||||
);
|
||||
});
|
||||
|
||||
it('generates relations for system entities', async () => {
|
||||
const entity: SystemEntity = {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
|
||||
@@ -32,6 +32,8 @@ import {
|
||||
RELATION_API_PROVIDED_BY,
|
||||
RELATION_CHILD_OF,
|
||||
RELATION_CONSUMES_API,
|
||||
RELATION_DEPENDENCY_OF,
|
||||
RELATION_DEPENDS_ON,
|
||||
RELATION_HAS_MEMBER,
|
||||
RELATION_HAS_PART,
|
||||
RELATION_MEMBER_OF,
|
||||
@@ -90,7 +92,7 @@ export class BuiltinKindsEntityProcessor implements CatalogProcessor {
|
||||
|
||||
function doEmit(
|
||||
targets: string | string[] | undefined,
|
||||
context: { defaultKind: string; defaultNamespace: string },
|
||||
context: { defaultKind?: string; defaultNamespace: string },
|
||||
outgoingRelation: string,
|
||||
incomingRelation: string,
|
||||
): void {
|
||||
@@ -99,16 +101,29 @@ export class BuiltinKindsEntityProcessor implements CatalogProcessor {
|
||||
}
|
||||
for (const target of [targets].flat()) {
|
||||
const targetRef = parseEntityRef(target, context);
|
||||
if (targetRef.kind === undefined) {
|
||||
throw new Error(
|
||||
`Entity reference "${target}" did not specify a kind (e.g. starting with "Component:"), and has no default`,
|
||||
);
|
||||
}
|
||||
emit(
|
||||
result.relation({
|
||||
source: selfRef,
|
||||
type: outgoingRelation,
|
||||
target: targetRef,
|
||||
target: {
|
||||
kind: targetRef.kind,
|
||||
namespace: targetRef.namespace,
|
||||
name: targetRef.name,
|
||||
},
|
||||
}),
|
||||
);
|
||||
emit(
|
||||
result.relation({
|
||||
source: targetRef,
|
||||
source: {
|
||||
kind: targetRef.kind,
|
||||
namespace: targetRef.namespace,
|
||||
name: targetRef.name,
|
||||
},
|
||||
type: incomingRelation,
|
||||
target: selfRef,
|
||||
}),
|
||||
@@ -146,6 +161,12 @@ export class BuiltinKindsEntityProcessor implements CatalogProcessor {
|
||||
RELATION_CONSUMES_API,
|
||||
RELATION_API_CONSUMED_BY,
|
||||
);
|
||||
doEmit(
|
||||
component.spec.dependsOn,
|
||||
{ defaultNamespace: selfRef.namespace },
|
||||
RELATION_DEPENDS_ON,
|
||||
RELATION_DEPENDENCY_OF,
|
||||
);
|
||||
doEmit(
|
||||
component.spec.system,
|
||||
{ defaultKind: 'System', defaultNamespace: selfRef.namespace },
|
||||
@@ -186,6 +207,12 @@ export class BuiltinKindsEntityProcessor implements CatalogProcessor {
|
||||
RELATION_OWNED_BY,
|
||||
RELATION_OWNER_OF,
|
||||
);
|
||||
doEmit(
|
||||
resource.spec.dependsOn,
|
||||
{ defaultNamespace: selfRef.namespace },
|
||||
RELATION_DEPENDS_ON,
|
||||
RELATION_DEPENDENCY_OF,
|
||||
);
|
||||
doEmit(
|
||||
resource.spec.system,
|
||||
{ defaultKind: 'System', defaultNamespace: selfRef.namespace },
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
import {
|
||||
Entity,
|
||||
RELATION_DEPENDS_ON,
|
||||
RELATION_PROVIDES_API,
|
||||
RELATION_PART_OF,
|
||||
serializeEntityRef,
|
||||
@@ -124,7 +125,6 @@ export function SystemDiagramCard() {
|
||||
catalogItem,
|
||||
RELATION_PROVIDES_API,
|
||||
);
|
||||
|
||||
catalogItemRelations_providesApi.forEach(foundRelation =>
|
||||
systemEdges.push({
|
||||
from: simplifiedEntityName(catalogItem),
|
||||
@@ -132,6 +132,18 @@ export function SystemDiagramCard() {
|
||||
label: 'provides API',
|
||||
}),
|
||||
);
|
||||
|
||||
const catalogItemRelations_dependsOn = getEntityRelations(
|
||||
catalogItem,
|
||||
RELATION_DEPENDS_ON,
|
||||
);
|
||||
catalogItemRelations_dependsOn.forEach(foundRelation =>
|
||||
systemEdges.push({
|
||||
from: simplifiedEntityName(catalogItem),
|
||||
to: simplifiedEntityName(foundRelation),
|
||||
label: 'depends on',
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user