Add system, domain and resource entity kinds
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/catalog-model': patch
|
||||
'@backstage/plugin-catalog-backend': patch
|
||||
---
|
||||
|
||||
Implement System, Domain and Resource entity kinds.
|
||||
+1
-1
@@ -127,7 +127,7 @@ integrations:
|
||||
|
||||
catalog:
|
||||
rules:
|
||||
- allow: [Component, API, Group, User, Template, Location]
|
||||
- allow: [Component, API, Resource, Group, User, Template, System, Domain, Location]
|
||||
|
||||
processors:
|
||||
githubOrg:
|
||||
|
||||
@@ -70,6 +70,7 @@ components:
|
||||
items:
|
||||
$ref: "#/components/schemas/Pet"
|
||||
`,
|
||||
system: 'system',
|
||||
},
|
||||
};
|
||||
});
|
||||
@@ -152,4 +153,19 @@ components:
|
||||
(entity as any).spec.definition = '';
|
||||
await expect(validator.check(entity)).rejects.toThrow(/definition/);
|
||||
});
|
||||
|
||||
it('accepts missing system', async () => {
|
||||
delete (entity as any).spec.system;
|
||||
await expect(validator.check(entity)).resolves.toBe(true);
|
||||
});
|
||||
|
||||
it('rejects wrong system', async () => {
|
||||
(entity as any).spec.system = 7;
|
||||
await expect(validator.check(entity)).rejects.toThrow(/system/);
|
||||
});
|
||||
|
||||
it('rejects empty system', async () => {
|
||||
(entity as any).spec.system = '';
|
||||
await expect(validator.check(entity)).rejects.toThrow(/system/);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -30,6 +30,7 @@ const schema = yup.object<Partial<ApiEntityV1alpha1>>({
|
||||
lifecycle: yup.string().required().min(1),
|
||||
owner: yup.string().required().min(1),
|
||||
definition: yup.string().required().min(1),
|
||||
system: yup.string().notRequired().min(1),
|
||||
})
|
||||
.required(),
|
||||
});
|
||||
@@ -42,6 +43,7 @@ export interface ApiEntityV1alpha1 extends Entity {
|
||||
lifecycle: string;
|
||||
owner: string;
|
||||
definition: string;
|
||||
system?: string;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ describe('ComponentV1alpha1Validator', () => {
|
||||
subcomponentOf: 'monolith',
|
||||
providesApis: ['api-0'],
|
||||
consumesApis: ['api-0'],
|
||||
system: 'system',
|
||||
},
|
||||
};
|
||||
});
|
||||
@@ -158,4 +159,19 @@ describe('ComponentV1alpha1Validator', () => {
|
||||
(entity as any).spec.consumesApis = [];
|
||||
await expect(validator.check(entity)).resolves.toBe(true);
|
||||
});
|
||||
|
||||
it('accepts missing system', async () => {
|
||||
delete (entity as any).spec.system;
|
||||
await expect(validator.check(entity)).resolves.toBe(true);
|
||||
});
|
||||
|
||||
it('rejects wrong system', async () => {
|
||||
(entity as any).spec.system = 7;
|
||||
await expect(validator.check(entity)).rejects.toThrow(/system/);
|
||||
});
|
||||
|
||||
it('rejects empty system', async () => {
|
||||
(entity as any).spec.system = '';
|
||||
await expect(validator.check(entity)).rejects.toThrow(/system/);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -32,6 +32,7 @@ const schema = yup.object<Partial<ComponentEntityV1alpha1>>({
|
||||
subcomponentOf: yup.string().notRequired().min(1),
|
||||
providesApis: yup.array(yup.string().required()).notRequired(),
|
||||
consumesApis: yup.array(yup.string().required()).notRequired(),
|
||||
system: yup.string().notRequired().min(1),
|
||||
})
|
||||
.required(),
|
||||
});
|
||||
@@ -46,6 +47,7 @@ export interface ComponentEntityV1alpha1 extends Entity {
|
||||
subcomponentOf?: string;
|
||||
providesApis?: string[];
|
||||
consumesApis?: string[];
|
||||
system?: string;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
DomainEntityV1alpha1,
|
||||
domainEntityV1alpha1Validator as validator,
|
||||
} from './DomainEntityV1alpha1';
|
||||
|
||||
describe('DomainV1alpha1Validator', () => {
|
||||
let entity: DomainEntityV1alpha1;
|
||||
|
||||
beforeEach(() => {
|
||||
entity = {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'Domain',
|
||||
metadata: {
|
||||
name: 'test',
|
||||
},
|
||||
spec: {
|
||||
owner: 'me',
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
it('happy path: accepts valid data', async () => {
|
||||
await expect(validator.check(entity)).resolves.toBe(true);
|
||||
});
|
||||
|
||||
it('silently accepts v1beta1 as well', async () => {
|
||||
(entity as any).apiVersion = 'backstage.io/v1beta1';
|
||||
await expect(validator.check(entity)).resolves.toBe(true);
|
||||
});
|
||||
|
||||
it('ignores unknown apiVersion', async () => {
|
||||
(entity as any).apiVersion = 'backstage.io/v1beta0';
|
||||
await expect(validator.check(entity)).resolves.toBe(false);
|
||||
});
|
||||
|
||||
it('ignores unknown kind', async () => {
|
||||
(entity as any).kind = 'Wizard';
|
||||
await expect(validator.check(entity)).resolves.toBe(false);
|
||||
});
|
||||
|
||||
it('rejects missing owner', async () => {
|
||||
delete (entity as any).spec.owner;
|
||||
await expect(validator.check(entity)).rejects.toThrow(/owner/);
|
||||
});
|
||||
|
||||
it('rejects wrong owner', async () => {
|
||||
(entity as any).spec.owner = 7;
|
||||
await expect(validator.check(entity)).rejects.toThrow(/owner/);
|
||||
});
|
||||
|
||||
it('rejects empty owner', async () => {
|
||||
(entity as any).spec.owner = '';
|
||||
await expect(validator.check(entity)).rejects.toThrow(/owner/);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as yup from 'yup';
|
||||
import type { Entity } from '../entity/Entity';
|
||||
import { schemaValidator } from './util';
|
||||
|
||||
const API_VERSION = ['backstage.io/v1alpha1', 'backstage.io/v1beta1'] as const;
|
||||
const KIND = 'Domain' as const;
|
||||
|
||||
const schema = yup.object<Partial<DomainEntityV1alpha1>>({
|
||||
apiVersion: yup.string().required().oneOf(API_VERSION),
|
||||
kind: yup.string().required().equals([KIND]),
|
||||
spec: yup
|
||||
.object({
|
||||
owner: yup.string().required().min(1),
|
||||
})
|
||||
.required(),
|
||||
});
|
||||
|
||||
export interface DomainEntityV1alpha1 extends Entity {
|
||||
apiVersion: typeof API_VERSION[number];
|
||||
kind: typeof KIND;
|
||||
spec: {
|
||||
owner: string;
|
||||
};
|
||||
}
|
||||
|
||||
export const domainEntityV1alpha1Validator = schemaValidator(
|
||||
KIND,
|
||||
API_VERSION,
|
||||
schema,
|
||||
);
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
ResourceEntityV1alpha1,
|
||||
resourceEntityV1alpha1Validator as validator,
|
||||
} from './ResourceEntityV1alpha1';
|
||||
|
||||
describe('ResourceV1alpha1Validator', () => {
|
||||
let entity: ResourceEntityV1alpha1;
|
||||
|
||||
beforeEach(() => {
|
||||
entity = {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'Resource',
|
||||
metadata: {
|
||||
name: 'test',
|
||||
},
|
||||
spec: {
|
||||
type: 'database',
|
||||
owner: 'me',
|
||||
system: 'system',
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
it('happy path: accepts valid data', async () => {
|
||||
await expect(validator.check(entity)).resolves.toBe(true);
|
||||
});
|
||||
|
||||
it('silently accepts v1beta1 as well', async () => {
|
||||
(entity as any).apiVersion = 'backstage.io/v1beta1';
|
||||
await expect(validator.check(entity)).resolves.toBe(true);
|
||||
});
|
||||
|
||||
it('ignores unknown apiVersion', async () => {
|
||||
(entity as any).apiVersion = 'backstage.io/v1beta0';
|
||||
await expect(validator.check(entity)).resolves.toBe(false);
|
||||
});
|
||||
|
||||
it('ignores unknown kind', async () => {
|
||||
(entity as any).kind = 'Wizard';
|
||||
await expect(validator.check(entity)).resolves.toBe(false);
|
||||
});
|
||||
|
||||
it('rejects missing type', async () => {
|
||||
delete (entity as any).spec.type;
|
||||
await expect(validator.check(entity)).rejects.toThrow(/type/);
|
||||
});
|
||||
|
||||
it('rejects wrong type', async () => {
|
||||
(entity as any).spec.type = 7;
|
||||
await expect(validator.check(entity)).rejects.toThrow(/type/);
|
||||
});
|
||||
|
||||
it('rejects empty type', async () => {
|
||||
(entity as any).spec.type = '';
|
||||
await expect(validator.check(entity)).rejects.toThrow(/type/);
|
||||
});
|
||||
|
||||
it('rejects missing owner', async () => {
|
||||
delete (entity as any).spec.owner;
|
||||
await expect(validator.check(entity)).rejects.toThrow(/owner/);
|
||||
});
|
||||
|
||||
it('rejects wrong owner', async () => {
|
||||
(entity as any).spec.owner = 7;
|
||||
await expect(validator.check(entity)).rejects.toThrow(/owner/);
|
||||
});
|
||||
|
||||
it('rejects empty owner', async () => {
|
||||
(entity as any).spec.owner = '';
|
||||
await expect(validator.check(entity)).rejects.toThrow(/owner/);
|
||||
});
|
||||
|
||||
it('accepts missing system', async () => {
|
||||
delete (entity as any).spec.system;
|
||||
await expect(validator.check(entity)).resolves.toBe(true);
|
||||
});
|
||||
|
||||
it('rejects wrong system', async () => {
|
||||
(entity as any).spec.system = 7;
|
||||
await expect(validator.check(entity)).rejects.toThrow(/system/);
|
||||
});
|
||||
|
||||
it('rejects empty system', async () => {
|
||||
(entity as any).spec.system = '';
|
||||
await expect(validator.check(entity)).rejects.toThrow(/system/);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as yup from 'yup';
|
||||
import type { Entity } from '../entity/Entity';
|
||||
import { schemaValidator } from './util';
|
||||
|
||||
const API_VERSION = ['backstage.io/v1alpha1', 'backstage.io/v1beta1'] as const;
|
||||
const KIND = 'Resource' as const;
|
||||
|
||||
const schema = yup.object<Partial<ResourceEntityV1alpha1>>({
|
||||
apiVersion: yup.string().required().oneOf(API_VERSION),
|
||||
kind: yup.string().required().equals([KIND]),
|
||||
spec: yup
|
||||
.object({
|
||||
type: yup.string().required().min(1),
|
||||
owner: yup.string().required().min(1),
|
||||
system: yup.string().notRequired().min(1),
|
||||
})
|
||||
.required(),
|
||||
});
|
||||
|
||||
export interface ResourceEntityV1alpha1 extends Entity {
|
||||
apiVersion: typeof API_VERSION[number];
|
||||
kind: typeof KIND;
|
||||
spec: {
|
||||
type: string;
|
||||
owner: string;
|
||||
system?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export const resourceEntityV1alpha1Validator = schemaValidator(
|
||||
KIND,
|
||||
API_VERSION,
|
||||
schema,
|
||||
);
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
SystemEntityV1alpha1,
|
||||
systemEntityV1alpha1Validator as validator,
|
||||
} from './SystemEntityV1alpha1';
|
||||
|
||||
describe('SystemV1alpha1Validator', () => {
|
||||
let entity: SystemEntityV1alpha1;
|
||||
|
||||
beforeEach(() => {
|
||||
entity = {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'System',
|
||||
metadata: {
|
||||
name: 'test',
|
||||
},
|
||||
spec: {
|
||||
owner: 'me',
|
||||
domain: 'domain',
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
it('happy path: accepts valid data', async () => {
|
||||
await expect(validator.check(entity)).resolves.toBe(true);
|
||||
});
|
||||
|
||||
it('silently accepts v1beta1 as well', async () => {
|
||||
(entity as any).apiVersion = 'backstage.io/v1beta1';
|
||||
await expect(validator.check(entity)).resolves.toBe(true);
|
||||
});
|
||||
|
||||
it('ignores unknown apiVersion', async () => {
|
||||
(entity as any).apiVersion = 'backstage.io/v1beta0';
|
||||
await expect(validator.check(entity)).resolves.toBe(false);
|
||||
});
|
||||
|
||||
it('ignores unknown kind', async () => {
|
||||
(entity as any).kind = 'Wizard';
|
||||
await expect(validator.check(entity)).resolves.toBe(false);
|
||||
});
|
||||
|
||||
it('rejects missing owner', async () => {
|
||||
delete (entity as any).spec.owner;
|
||||
await expect(validator.check(entity)).rejects.toThrow(/owner/);
|
||||
});
|
||||
|
||||
it('rejects wrong owner', async () => {
|
||||
(entity as any).spec.owner = 7;
|
||||
await expect(validator.check(entity)).rejects.toThrow(/owner/);
|
||||
});
|
||||
|
||||
it('rejects empty owner', async () => {
|
||||
(entity as any).spec.owner = '';
|
||||
await expect(validator.check(entity)).rejects.toThrow(/owner/);
|
||||
});
|
||||
|
||||
it('accepts missing domain', async () => {
|
||||
delete (entity as any).spec.domain;
|
||||
await expect(validator.check(entity)).resolves.toBe(true);
|
||||
});
|
||||
|
||||
it('rejects wrong domain', async () => {
|
||||
(entity as any).spec.domain = 7;
|
||||
await expect(validator.check(entity)).rejects.toThrow(/domain/);
|
||||
});
|
||||
|
||||
it('rejects empty domain', async () => {
|
||||
(entity as any).spec.domain = '';
|
||||
await expect(validator.check(entity)).rejects.toThrow(/domain/);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as yup from 'yup';
|
||||
import type { Entity } from '../entity/Entity';
|
||||
import { schemaValidator } from './util';
|
||||
|
||||
const API_VERSION = ['backstage.io/v1alpha1', 'backstage.io/v1beta1'] as const;
|
||||
const KIND = 'System' as const;
|
||||
|
||||
const schema = yup.object<Partial<SystemEntityV1alpha1>>({
|
||||
apiVersion: yup.string().required().oneOf(API_VERSION),
|
||||
kind: yup.string().required().equals([KIND]),
|
||||
spec: yup
|
||||
.object({
|
||||
owner: yup.string().required().min(1),
|
||||
domain: yup.string().notRequired().min(1),
|
||||
})
|
||||
.required(),
|
||||
});
|
||||
|
||||
export interface SystemEntityV1alpha1 extends Entity {
|
||||
apiVersion: typeof API_VERSION[number];
|
||||
kind: typeof KIND;
|
||||
spec: {
|
||||
owner: string;
|
||||
domain?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export const systemEntityV1alpha1Validator = schemaValidator(
|
||||
KIND,
|
||||
API_VERSION,
|
||||
schema,
|
||||
);
|
||||
@@ -26,6 +26,11 @@ export type {
|
||||
ComponentEntityV1alpha1 as ComponentEntity,
|
||||
ComponentEntityV1alpha1,
|
||||
} from './ComponentEntityV1alpha1';
|
||||
export { domainEntityV1alpha1Validator } from './DomainEntityV1alpha1';
|
||||
export type {
|
||||
DomainEntityV1alpha1 as DomainEntity,
|
||||
DomainEntityV1alpha1,
|
||||
} from './DomainEntityV1alpha1';
|
||||
export { groupEntityV1alpha1Validator } from './GroupEntityV1alpha1';
|
||||
export type {
|
||||
GroupEntityV1alpha1 as GroupEntity,
|
||||
@@ -37,6 +42,16 @@ export type {
|
||||
LocationEntityV1alpha1,
|
||||
} from './LocationEntityV1alpha1';
|
||||
export * from './relations';
|
||||
export { resourceEntityV1alpha1Validator } from './ResourceEntityV1alpha1';
|
||||
export type {
|
||||
ResourceEntityV1alpha1 as ResourceEntity,
|
||||
ResourceEntityV1alpha1,
|
||||
} from './ResourceEntityV1alpha1';
|
||||
export { systemEntityV1alpha1Validator } from './SystemEntityV1alpha1';
|
||||
export type {
|
||||
SystemEntityV1alpha1 as SystemEntity,
|
||||
SystemEntityV1alpha1,
|
||||
} from './SystemEntityV1alpha1';
|
||||
export { templateEntityV1alpha1Validator } from './TemplateEntityV1alpha1';
|
||||
export type {
|
||||
TemplateEntityV1alpha1 as TemplateEntity,
|
||||
|
||||
@@ -30,7 +30,7 @@ export const RELATION_OWNED_BY = 'ownedBy';
|
||||
export const RELATION_OWNER_OF = 'ownerOf';
|
||||
|
||||
/**
|
||||
* A relation with an API entity, typically from a component or system
|
||||
* A relation with an API entity, typically from a component
|
||||
*/
|
||||
export const RELATION_CONSUMES_API = 'consumesApi';
|
||||
export const RELATION_API_CONSUMED_BY = 'apiConsumedBy';
|
||||
@@ -57,8 +57,13 @@ export const RELATION_MEMBER_OF = 'memberOf';
|
||||
export const RELATION_HAS_MEMBER = 'hasMember';
|
||||
|
||||
/**
|
||||
<<<<<<< HEAD
|
||||
* A part/whole relation, typically for components in a system and systems
|
||||
* in a domain.
|
||||
=======
|
||||
* A grouping relation, typically for components, resources or APIs in a
|
||||
* system, or for systems inside a domain.
|
||||
>>>>>>> Add system, domain and resource entity kinds
|
||||
*/
|
||||
export const RELATION_PART_OF = 'partOf';
|
||||
export const RELATION_HAS_PART = 'hasPart';
|
||||
|
||||
+167
-2
@@ -17,7 +17,10 @@
|
||||
import {
|
||||
ApiEntity,
|
||||
ComponentEntity,
|
||||
DomainEntity,
|
||||
GroupEntity,
|
||||
ResourceEntity,
|
||||
SystemEntity,
|
||||
UserEntity,
|
||||
} from '@backstage/catalog-model';
|
||||
import { BuiltinKindsEntityProcessor } from './BuiltinKindsEntityProcessor';
|
||||
@@ -42,12 +45,13 @@ describe('BuiltinKindsEntityProcessor', () => {
|
||||
lifecycle: 'l',
|
||||
providesApis: ['b'],
|
||||
consumesApis: ['c'],
|
||||
system: 's',
|
||||
},
|
||||
};
|
||||
|
||||
await processor.postProcessEntity(entity, location, emit);
|
||||
|
||||
expect(emit).toBeCalledTimes(8);
|
||||
expect(emit).toBeCalledTimes(10);
|
||||
expect(emit).toBeCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
@@ -112,6 +116,22 @@ describe('BuiltinKindsEntityProcessor', () => {
|
||||
target: { kind: 'Component', namespace: 'default', name: 's' },
|
||||
},
|
||||
});
|
||||
expect(emit).toBeCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
source: { kind: 'System', namespace: 'default', name: 's' },
|
||||
type: 'hasPart',
|
||||
target: { kind: 'Component', namespace: 'default', name: 'n' },
|
||||
},
|
||||
});
|
||||
expect(emit).toBeCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
source: { kind: 'Component', namespace: 'default', name: 'n' },
|
||||
type: 'partOf',
|
||||
target: { kind: 'System', namespace: 'default', name: 's' },
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('generates relations for api entities', async () => {
|
||||
@@ -124,12 +144,13 @@ describe('BuiltinKindsEntityProcessor', () => {
|
||||
owner: 'o',
|
||||
lifecycle: 'l',
|
||||
definition: 'd',
|
||||
system: 's',
|
||||
},
|
||||
};
|
||||
|
||||
await processor.postProcessEntity(entity, location, emit);
|
||||
|
||||
expect(emit).toBeCalledTimes(2);
|
||||
expect(emit).toBeCalledTimes(4);
|
||||
expect(emit).toBeCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
@@ -146,6 +167,150 @@ describe('BuiltinKindsEntityProcessor', () => {
|
||||
target: { kind: 'Group', namespace: 'default', name: 'o' },
|
||||
},
|
||||
});
|
||||
expect(emit).toBeCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
source: { kind: 'System', namespace: 'default', name: 's' },
|
||||
type: 'hasPart',
|
||||
target: { kind: 'API', namespace: 'default', name: 'n' },
|
||||
},
|
||||
});
|
||||
expect(emit).toBeCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
source: { kind: 'API', namespace: 'default', name: 'n' },
|
||||
type: 'partOf',
|
||||
target: { kind: 'System', namespace: 'default', name: 's' },
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('generates relations for resource entities', async () => {
|
||||
const entity: ResourceEntity = {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'Resource',
|
||||
metadata: { name: 'n' },
|
||||
spec: {
|
||||
type: 'database',
|
||||
owner: 'o',
|
||||
system: 's',
|
||||
},
|
||||
};
|
||||
|
||||
await processor.postProcessEntity(entity, location, emit);
|
||||
|
||||
expect(emit).toBeCalledTimes(4);
|
||||
expect(emit).toBeCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
source: { kind: 'Group', namespace: 'default', name: 'o' },
|
||||
type: 'ownerOf',
|
||||
target: { kind: 'Resource', namespace: 'default', name: 'n' },
|
||||
},
|
||||
});
|
||||
expect(emit).toBeCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
source: { kind: 'Resource', namespace: 'default', name: 'n' },
|
||||
type: 'ownedBy',
|
||||
target: { kind: 'Group', namespace: 'default', name: 'o' },
|
||||
},
|
||||
});
|
||||
expect(emit).toBeCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
source: { kind: 'System', namespace: 'default', name: 's' },
|
||||
type: 'hasPart',
|
||||
target: { kind: 'Resource', namespace: 'default', name: 'n' },
|
||||
},
|
||||
});
|
||||
expect(emit).toBeCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
source: { kind: 'Resource', namespace: 'default', name: 'n' },
|
||||
type: 'partOf',
|
||||
target: { kind: 'System', namespace: 'default', name: 's' },
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('generates relations for system entities', async () => {
|
||||
const entity: SystemEntity = {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'System',
|
||||
metadata: { name: 'n' },
|
||||
spec: {
|
||||
owner: 'o',
|
||||
domain: 'd',
|
||||
},
|
||||
};
|
||||
|
||||
await processor.postProcessEntity(entity, location, emit);
|
||||
|
||||
expect(emit).toBeCalledTimes(4);
|
||||
expect(emit).toBeCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
source: { kind: 'Group', namespace: 'default', name: 'o' },
|
||||
type: 'ownerOf',
|
||||
target: { kind: 'System', namespace: 'default', name: 'n' },
|
||||
},
|
||||
});
|
||||
expect(emit).toBeCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
source: { kind: 'System', namespace: 'default', name: 'n' },
|
||||
type: 'ownedBy',
|
||||
target: { kind: 'Group', namespace: 'default', name: 'o' },
|
||||
},
|
||||
});
|
||||
expect(emit).toBeCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
source: { kind: 'Domain', namespace: 'default', name: 'd' },
|
||||
type: 'hasPart',
|
||||
target: { kind: 'System', namespace: 'default', name: 'n' },
|
||||
},
|
||||
});
|
||||
expect(emit).toBeCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
source: { kind: 'System', namespace: 'default', name: 'n' },
|
||||
type: 'partOf',
|
||||
target: { kind: 'Domain', namespace: 'default', name: 'd' },
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('generates relations for domain entities', async () => {
|
||||
const entity: DomainEntity = {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'Domain',
|
||||
metadata: { name: 'n' },
|
||||
spec: {
|
||||
owner: 'o',
|
||||
},
|
||||
};
|
||||
|
||||
await processor.postProcessEntity(entity, location, emit);
|
||||
|
||||
expect(emit).toBeCalledTimes(2);
|
||||
expect(emit).toBeCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
source: { kind: 'Group', namespace: 'default', name: 'o' },
|
||||
type: 'ownerOf',
|
||||
target: { kind: 'Domain', namespace: 'default', name: 'n' },
|
||||
},
|
||||
});
|
||||
expect(emit).toBeCalledWith({
|
||||
type: 'relation',
|
||||
relation: {
|
||||
source: { kind: 'Domain', namespace: 'default', name: 'n' },
|
||||
type: 'ownedBy',
|
||||
target: { kind: 'Group', namespace: 'default', name: 'o' },
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('generates relations for user entities', async () => {
|
||||
|
||||
@@ -19,6 +19,8 @@ import {
|
||||
apiEntityV1alpha1Validator,
|
||||
ComponentEntity,
|
||||
componentEntityV1alpha1Validator,
|
||||
DomainEntity,
|
||||
domainEntityV1alpha1Validator,
|
||||
Entity,
|
||||
getEntityName,
|
||||
GroupEntity,
|
||||
@@ -31,13 +33,17 @@ import {
|
||||
RELATION_CHILD_OF,
|
||||
RELATION_CONSUMES_API,
|
||||
RELATION_HAS_MEMBER,
|
||||
RELATION_MEMBER_OF,
|
||||
RELATION_HAS_PART,
|
||||
RELATION_PART_OF,
|
||||
RELATION_MEMBER_OF,
|
||||
RELATION_OWNED_BY,
|
||||
RELATION_OWNER_OF,
|
||||
RELATION_PARENT_OF,
|
||||
RELATION_PART_OF,
|
||||
RELATION_PROVIDES_API,
|
||||
ResourceEntity,
|
||||
resourceEntityV1alpha1Validator,
|
||||
SystemEntity,
|
||||
systemEntityV1alpha1Validator,
|
||||
templateEntityV1alpha1Validator,
|
||||
UserEntity,
|
||||
userEntityV1alpha1Validator,
|
||||
@@ -49,10 +55,13 @@ export class BuiltinKindsEntityProcessor implements CatalogProcessor {
|
||||
private readonly validators = [
|
||||
apiEntityV1alpha1Validator,
|
||||
componentEntityV1alpha1Validator,
|
||||
resourceEntityV1alpha1Validator,
|
||||
groupEntityV1alpha1Validator,
|
||||
locationEntityV1alpha1Validator,
|
||||
templateEntityV1alpha1Validator,
|
||||
userEntityV1alpha1Validator,
|
||||
systemEntityV1alpha1Validator,
|
||||
domainEntityV1alpha1Validator,
|
||||
];
|
||||
|
||||
async validateEntityKind(entity: Entity): Promise<boolean> {
|
||||
@@ -135,6 +144,12 @@ export class BuiltinKindsEntityProcessor implements CatalogProcessor {
|
||||
RELATION_CONSUMES_API,
|
||||
RELATION_API_CONSUMED_BY,
|
||||
);
|
||||
doEmit(
|
||||
component.spec.system,
|
||||
{ defaultKind: 'System', defaultNamespace: selfRef.namespace },
|
||||
RELATION_PART_OF,
|
||||
RELATION_HAS_PART,
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -149,6 +164,32 @@ export class BuiltinKindsEntityProcessor implements CatalogProcessor {
|
||||
RELATION_OWNED_BY,
|
||||
RELATION_OWNER_OF,
|
||||
);
|
||||
doEmit(
|
||||
api.spec.system,
|
||||
{ defaultKind: 'System', defaultNamespace: selfRef.namespace },
|
||||
RELATION_PART_OF,
|
||||
RELATION_HAS_PART,
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Emit relations for the Resource kind
|
||||
*/
|
||||
|
||||
if (entity.kind === 'Resource') {
|
||||
const resource = entity as ResourceEntity;
|
||||
doEmit(
|
||||
resource.spec.owner,
|
||||
{ defaultKind: 'Group', defaultNamespace: selfRef.namespace },
|
||||
RELATION_OWNED_BY,
|
||||
RELATION_OWNER_OF,
|
||||
);
|
||||
doEmit(
|
||||
resource.spec.system,
|
||||
{ defaultKind: 'System', defaultNamespace: selfRef.namespace },
|
||||
RELATION_PART_OF,
|
||||
RELATION_HAS_PART,
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -185,6 +226,40 @@ export class BuiltinKindsEntityProcessor implements CatalogProcessor {
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Emit relations for the System kind
|
||||
*/
|
||||
|
||||
if (entity.kind === 'System') {
|
||||
const system = entity as SystemEntity;
|
||||
doEmit(
|
||||
system.spec.owner,
|
||||
{ defaultKind: 'Group', defaultNamespace: selfRef.namespace },
|
||||
RELATION_OWNED_BY,
|
||||
RELATION_OWNER_OF,
|
||||
);
|
||||
doEmit(
|
||||
system.spec.domain,
|
||||
{ defaultKind: 'Domain', defaultNamespace: selfRef.namespace },
|
||||
RELATION_PART_OF,
|
||||
RELATION_HAS_PART,
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Emit relations for the Domain kind
|
||||
*/
|
||||
|
||||
if (entity.kind === 'Domain') {
|
||||
const domain = entity as DomainEntity;
|
||||
doEmit(
|
||||
domain.spec.owner,
|
||||
{ defaultKind: 'Group', defaultNamespace: selfRef.namespace },
|
||||
RELATION_OWNED_BY,
|
||||
RELATION_OWNER_OF,
|
||||
);
|
||||
}
|
||||
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user