From 8488a1a9697651625867779984178f19d7a366cb Mon Sep 17 00:00:00 2001 From: Jonah Grimes Date: Sun, 28 Mar 2021 21:22:36 -0400 Subject: [PATCH 1/3] added support for the 'members' field of the Group entity, allowing specification of direct members from the Group side of the relationship. added support to the BuiltinKindsEntityProcessor to generate the appropriate relationships. updated documentation. Signed-off-by: Jonah Grimes --- .changeset/swift-lobsters-learn.md | 6 +++++ .../software-catalog/descriptor-format.md | 13 +++++++++++ .../src/kinds/GroupEntityV1alpha1.test.ts | 22 +++++++++++++++++++ .../src/kinds/GroupEntityV1alpha1.ts | 1 + .../schema/kinds/Group.v1alpha1.schema.json | 9 ++++++++ .../BuiltinKindsEntityProcessor.test.ts | 19 +++++++++++++++- .../processors/BuiltinKindsEntityProcessor.ts | 6 +++++ 7 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 .changeset/swift-lobsters-learn.md diff --git a/.changeset/swift-lobsters-learn.md b/.changeset/swift-lobsters-learn.md new file mode 100644 index 0000000000..e5adfde478 --- /dev/null +++ b/.changeset/swift-lobsters-learn.md @@ -0,0 +1,6 @@ +--- +'@backstage/catalog-model': patch +'@backstage/plugin-catalog-backend': patch +--- + +Added support for the "members" field of the Group entity, allowing specification of direct members from the Group side of the relationship. Added support to the BuiltinKindsEntityProcessor to generate the appropriate relationships. diff --git a/docs/features/software-catalog/descriptor-format.md b/docs/features/software-catalog/descriptor-format.md index e4b046d76f..5c06401642 100644 --- a/docs/features/software-catalog/descriptor-format.md +++ b/docs/features/software-catalog/descriptor-format.md @@ -808,6 +808,7 @@ spec: picture: https://example.com/groups/bu-infrastructure.jpeg parent: ops children: [backstage, other] + members: [jdoe] ``` In addition to the [common envelope metadata](#common-to-all-kinds-the-metadata) @@ -865,6 +866,18 @@ The entries of this array are | --------------------------------------- | ------------------------------------------ | ------------------------------------------------------------------------------------- | | [`Group`](#kind-group) (default) | Same as this entity, typically `default` | [`hasMember`, and reverse `memberOf`](well-known-relations.md#memberof-and-hasmember) | +### `spec.members` [optional] + +The users that are direct members of this group. The items are not guaranteed to +be ordered in any particular way. + +The entries of this array are +[entity references](https://backstage.io/docs/features/software-catalog/references). + +| [`kind`](#apiversion-and-kind-required) | Default [`namespace`](#namespace-optional) | Generated [relation](well-known-relations.md) type | +| --------------------------------------- | ------------------------------------------ | ------------------------------------------------------------------------------------- | +| [`User`](#kind-group) (default) | Same as this entity, typically `default` | [`hasMember`, and reverse `memberOf`](well-known-relations.md#memberof-and-hasmember) | + ## Kind: User Describes the following entity kind: diff --git a/packages/catalog-model/src/kinds/GroupEntityV1alpha1.test.ts b/packages/catalog-model/src/kinds/GroupEntityV1alpha1.test.ts index b25795cd31..aa8011e977 100644 --- a/packages/catalog-model/src/kinds/GroupEntityV1alpha1.test.ts +++ b/packages/catalog-model/src/kinds/GroupEntityV1alpha1.test.ts @@ -172,4 +172,26 @@ describe('GroupV1alpha1Validator', () => { (entity as any).spec.children = []; await expect(validator.check(entity)).resolves.toBe(true); }); + + // members + + it('accepts missing members', async () => { + delete (entity as any).spec.members; + await expect(validator.check(entity)).resolves.toBe(true); + }); + + it('rejects empty members', async () => { + (entity as any).spec.members = ['']; + await expect(validator.check(entity)).rejects.toThrow(/members/); + }); + + it('rejects undefined members', async () => { + (entity as any).spec.members = [undefined]; + await expect(validator.check(entity)).rejects.toThrow(/members/); + }); + + it('accepts no members', async () => { + (entity as any).spec.members = []; + await expect(validator.check(entity)).resolves.toBe(true); + }); }); diff --git a/packages/catalog-model/src/kinds/GroupEntityV1alpha1.ts b/packages/catalog-model/src/kinds/GroupEntityV1alpha1.ts index d039fdaba8..74ca4f221a 100644 --- a/packages/catalog-model/src/kinds/GroupEntityV1alpha1.ts +++ b/packages/catalog-model/src/kinds/GroupEntityV1alpha1.ts @@ -36,6 +36,7 @@ export interface GroupEntityV1alpha1 extends Entity { }; parent?: string; children: string[]; + members?: string[]; }; } diff --git a/packages/catalog-model/src/schema/kinds/Group.v1alpha1.schema.json b/packages/catalog-model/src/schema/kinds/Group.v1alpha1.schema.json index fc19d98301..14c9d27eef 100644 --- a/packages/catalog-model/src/schema/kinds/Group.v1alpha1.schema.json +++ b/packages/catalog-model/src/schema/kinds/Group.v1alpha1.schema.json @@ -86,6 +86,15 @@ "examples": ["backstage", "other"], "minLength": 1 } + }, + "members": { + "type": "array", + "description": "The users that are members of this group. The entries of this array are entity references.", + "items": { + "type": "string", + "examples": ["jdoe"], + "minLength": 1 + } } } } diff --git a/plugins/catalog-backend/src/ingestion/processors/BuiltinKindsEntityProcessor.test.ts b/plugins/catalog-backend/src/ingestion/processors/BuiltinKindsEntityProcessor.test.ts index feb4791477..2162272390 100644 --- a/plugins/catalog-backend/src/ingestion/processors/BuiltinKindsEntityProcessor.test.ts +++ b/plugins/catalog-backend/src/ingestion/processors/BuiltinKindsEntityProcessor.test.ts @@ -353,12 +353,13 @@ describe('BuiltinKindsEntityProcessor', () => { type: 't', parent: 'p', children: ['c'], + members: ['m'], }, }; await processor.postProcessEntity(entity, location, emit); - expect(emit).toBeCalledTimes(4); + expect(emit).toBeCalledTimes(6); expect(emit).toBeCalledWith({ type: 'relation', relation: { @@ -391,6 +392,22 @@ describe('BuiltinKindsEntityProcessor', () => { target: { kind: 'Group', namespace: 'default', name: 'c' }, }, }); + expect(emit).toBeCalledWith({ + type: 'relation', + relation: { + source: { kind: 'User', namespace: 'default', name: 'm' }, + type: 'memberOf', + target: { kind: 'Group', namespace: 'default', name: 'n' }, + }, + }); + expect(emit).toBeCalledWith({ + type: 'relation', + relation: { + source: { kind: 'Group', namespace: 'default', name: 'n' }, + type: 'hasMember', + target: { kind: 'User', namespace: 'default', name: 'm' }, + }, + }); }); }); }); diff --git a/plugins/catalog-backend/src/ingestion/processors/BuiltinKindsEntityProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/BuiltinKindsEntityProcessor.ts index 26a8538707..64a47127f9 100644 --- a/plugins/catalog-backend/src/ingestion/processors/BuiltinKindsEntityProcessor.ts +++ b/plugins/catalog-backend/src/ingestion/processors/BuiltinKindsEntityProcessor.ts @@ -226,6 +226,12 @@ export class BuiltinKindsEntityProcessor implements CatalogProcessor { RELATION_PARENT_OF, RELATION_CHILD_OF, ); + doEmit( + group.spec.members, + { defaultKind: 'User', defaultNamespace: selfRef.namespace }, + RELATION_HAS_MEMBER, + RELATION_MEMBER_OF, + ); } /* From 35cee069a9f203f218db7ba1b09eaaeba8e88d01 Mon Sep 17 00:00:00 2001 From: Jonah Grimes Date: Sun, 28 Mar 2021 22:02:09 -0400 Subject: [PATCH 2/3] fixed documentation link for kind-user Signed-off-by: Jonah Grimes --- docs/features/software-catalog/descriptor-format.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/software-catalog/descriptor-format.md b/docs/features/software-catalog/descriptor-format.md index 5c06401642..7397ce7d23 100644 --- a/docs/features/software-catalog/descriptor-format.md +++ b/docs/features/software-catalog/descriptor-format.md @@ -876,7 +876,7 @@ The entries of this array are | [`kind`](#apiversion-and-kind-required) | Default [`namespace`](#namespace-optional) | Generated [relation](well-known-relations.md) type | | --------------------------------------- | ------------------------------------------ | ------------------------------------------------------------------------------------- | -| [`User`](#kind-group) (default) | Same as this entity, typically `default` | [`hasMember`, and reverse `memberOf`](well-known-relations.md#memberof-and-hasmember) | +| [`User`](#kind-user) (default) | Same as this entity, typically `default` | [`hasMember`, and reverse `memberOf`](well-known-relations.md#memberof-and-hasmember) | ## Kind: User From e1e0809162c04487f7ef2342384198c430df8051 Mon Sep 17 00:00:00 2001 From: Jonah Grimes Date: Mon, 29 Mar 2021 12:56:07 -0400 Subject: [PATCH 3/3] added happy path testing, reformatted changeset Signed-off-by: Jonah Grimes --- .changeset/swift-lobsters-learn.md | 4 +++- packages/catalog-model/src/kinds/GroupEntityV1alpha1.test.ts | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.changeset/swift-lobsters-learn.md b/.changeset/swift-lobsters-learn.md index e5adfde478..afdc4e1146 100644 --- a/.changeset/swift-lobsters-learn.md +++ b/.changeset/swift-lobsters-learn.md @@ -3,4 +3,6 @@ '@backstage/plugin-catalog-backend': patch --- -Added support for the "members" field of the Group entity, allowing specification of direct members from the Group side of the relationship. Added support to the BuiltinKindsEntityProcessor to generate the appropriate relationships. +Added support for the "members" field of the Group entity, allowing specification of +direct members from the Group side of the relationship. Added support to the +`BuiltinKindsEntityProcessor` to generate the appropriate relationships. diff --git a/packages/catalog-model/src/kinds/GroupEntityV1alpha1.test.ts b/packages/catalog-model/src/kinds/GroupEntityV1alpha1.test.ts index aa8011e977..6e59637c67 100644 --- a/packages/catalog-model/src/kinds/GroupEntityV1alpha1.test.ts +++ b/packages/catalog-model/src/kinds/GroupEntityV1alpha1.test.ts @@ -39,6 +39,7 @@ describe('GroupV1alpha1Validator', () => { }, parent: 'group-a', children: ['child-a', 'child-b'], + members: ['jdoe'], }, }; });