Add profile section to group entity

This commit is contained in:
Oliver Sand
2020-12-08 14:09:01 +01:00
parent 43931a5ff5
commit c911061b75
4 changed files with 101 additions and 1 deletions
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/catalog-model': patch
---
Introduce a `profile` section for group entities that can optional include a
`displayName`, `email` and `picture`.
@@ -723,6 +723,10 @@ metadata:
description: The infra business unit
spec:
type: business-unit
profile:
displayName: Infrastructure
email: infrastructure@example.com
picture: https://example.com/groups/bu-infrastructure.jpeg
parent: ops
children: [backstage, other]
```
@@ -747,6 +751,14 @@ Some common values for this field could be:
- `product-area`
- `root` - as a common virtual root of the hierarchy, if desired
### `spec.profile` [optional]
Optional profile information about the group, mainly for display purposes. All
fields of this structure are also optional. The email would be a group email of
some form, that the group may wish to be used for contacting them. The picture
is expected to be a URL pointing to an image that's representative of the group,
and that a browser could fetch and render on a group page or similar.
### `spec.parent` [optional]
The immediate parent group in the hierarchy, if any. Not all groups must have a
@@ -28,11 +28,15 @@ describe('GroupV1alpha1Validator', () => {
kind: 'Group',
metadata: {
name: 'doe-squad',
title: 'Doe Squad',
description: 'A squad for John and Jane',
},
spec: {
type: 'squad',
profile: {
displayName: 'Doe Squad',
email: 'doe@doe.org',
picture: 'https://doe.org/doe',
},
parent: 'group-a',
children: ['child-a', 'child-b'],
},
@@ -73,6 +77,70 @@ describe('GroupV1alpha1Validator', () => {
await expect(validator.check(entity)).rejects.toThrow(/type/);
});
// profile
it('accepts missing profile', async () => {
delete (entity as any).spec.profile;
await expect(validator.check(entity)).resolves.toBe(true);
});
it('rejects wrong profile', async () => {
(entity as any).spec.profile = 7;
await expect(validator.check(entity)).rejects.toThrow(/profile/);
});
it('profile accepts missing displayName', async () => {
delete (entity as any).spec.profile.displayName;
await expect(validator.check(entity)).resolves.toBe(true);
});
it('profile rejects wrong displayName', async () => {
(entity as any).spec.profile.displayName = 7;
await expect(validator.check(entity)).rejects.toThrow(/displayName/);
});
it('profile rejects empty displayName', async () => {
(entity as any).spec.profile.displayName = '';
await expect(validator.check(entity)).rejects.toThrow(/displayName/);
});
it('profile accepts missing email', async () => {
delete (entity as any).spec.profile.email;
await expect(validator.check(entity)).resolves.toBe(true);
});
it('profile rejects wrong email', async () => {
(entity as any).spec.profile.email = 7;
await expect(validator.check(entity)).rejects.toThrow(/email/);
});
it('profile rejects empty email', async () => {
(entity as any).spec.profile.email = '';
await expect(validator.check(entity)).rejects.toThrow(/email/);
});
it('profile accepts missing picture', async () => {
delete (entity as any).spec.profile.picture;
await expect(validator.check(entity)).resolves.toBe(true);
});
it('profile rejects wrong picture', async () => {
(entity as any).spec.profile.picture = 7;
await expect(validator.check(entity)).rejects.toThrow(/picture/);
});
it('profile rejects empty picture', async () => {
(entity as any).spec.profile.picture = '';
await expect(validator.check(entity)).rejects.toThrow(/picture/);
});
it('profile accepts unknown additional fields', async () => {
(entity as any).spec.profile.foo = 'data';
await expect(validator.check(entity)).resolves.toBe(true);
});
// parent
it('accepts missing parent', async () => {
delete (entity as any).spec.parent;
await expect(validator.check(entity)).resolves.toBe(true);
@@ -83,6 +151,8 @@ describe('GroupV1alpha1Validator', () => {
await expect(validator.check(entity)).rejects.toThrow(/parent/);
});
// children
it('rejects missing children', async () => {
delete (entity as any).spec.children;
await expect(validator.check(entity)).rejects.toThrow(/children/);
@@ -27,6 +27,13 @@ const schema = yup.object<Partial<GroupEntityV1alpha1>>({
spec: yup
.object({
type: yup.string().required().min(1),
profile: yup
.object({
displayName: yup.string().min(1).notRequired(),
email: yup.string().min(1).notRequired(),
picture: yup.string().min(1).notRequired(),
})
.notRequired(),
parent: yup.string().notRequired().min(1),
// Use these manual tests because yup .required() requires at least
// one element and there is no simple workaround -_-
@@ -46,6 +53,11 @@ export interface GroupEntityV1alpha1 extends Entity {
kind: typeof KIND;
spec: {
type: string;
profile?: {
displayName?: string;
email?: string;
picture?: string;
};
parent?: string;
children: string[];
};