From 26371bba78c695bae1561d31ee715e6239685a08 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Wed, 21 Oct 2020 12:35:04 +0200 Subject: [PATCH] catalog-backend: revert GroupPopulatorProc, replace with OwnerRelationProc + relation consts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: blam Co-authored-by: Fredrik Adelöw --- dev-components.yaml | 38 ----------- .../src/kinds/GroupEntityV1alpha1.ts | 30 ++++----- .../src/kinds/UserEntityV1alpha1.ts | 10 +-- packages/catalog-model/src/kinds/index.ts | 1 + packages/catalog-model/src/kinds/relations.ts | 55 +++++++++++++++ ...Processor.ts => OwnerRelationProcessor.ts} | 67 +++++++++---------- .../src/ingestion/processors/index.ts | 2 +- .../src/service/CatalogBuilder.ts | 4 +- 8 files changed, 110 insertions(+), 97 deletions(-) delete mode 100644 dev-components.yaml create mode 100644 packages/catalog-model/src/kinds/relations.ts rename plugins/catalog-backend/src/ingestion/processors/{GroupPopulatorProcessor.ts => OwnerRelationProcessor.ts} (52%) diff --git a/dev-components.yaml b/dev-components.yaml deleted file mode 100644 index 1671f6057f..0000000000 --- a/dev-components.yaml +++ /dev/null @@ -1,38 +0,0 @@ -apiVersion: backstage.io/v1alpha1 -kind: Group -metadata: - name: root -spec: - type: org ---- -apiVersion: backstage.io/v1alpha1 -kind: Group -metadata: - name: platform -spec: - type: mission - parent: root -# --- -# apiVersion: backstage.io/v1alpha1 -# kind: Group -# metadata: -# name: pdx -# spec: -# type: tribe -# parent: platform -# --- -# apiVersion: backstage.io/v1alpha1 -# kind: Group -# metadata: -# name: tools -# spec: -# type: squad -# parent: pdx -# --- -# apiVersion: backstage.io/v1alpha1 -# kind: Group -# metadata: -# name: pulp-fiction -# spec: -# type: squad -# parent: pdx diff --git a/packages/catalog-model/src/kinds/GroupEntityV1alpha1.ts b/packages/catalog-model/src/kinds/GroupEntityV1alpha1.ts index 8d1fbe78e8..f0e91ddce8 100644 --- a/packages/catalog-model/src/kinds/GroupEntityV1alpha1.ts +++ b/packages/catalog-model/src/kinds/GroupEntityV1alpha1.ts @@ -32,21 +32,21 @@ const schema = yup.object>({ // one element and there is no simple workaround -_- // the cast is there to convince typescript that the array itself is // required without using .required() - // ancestors: yup.array(yup.string().required()).test({ - // name: 'isDefined', - // message: 'ancestors must be defined', - // test: v => Boolean(v), - // }) as yup.ArraySchema, - // children: yup.array(yup.string().required()).test({ - // name: 'isDefined', - // message: 'children must be defined', - // test: v => Boolean(v), - // }) as yup.ArraySchema, - // descendants: yup.array(yup.string().required()).test({ - // name: 'isDefined', - // message: 'descendants must be defined', - // test: v => Boolean(v), - // }) as yup.ArraySchema, + ancestors: yup.array(yup.string().required()).test({ + name: 'isDefined', + message: 'ancestors must be defined', + test: v => Boolean(v), + }) as yup.ArraySchema, + children: yup.array(yup.string().required()).test({ + name: 'isDefined', + message: 'children must be defined', + test: v => Boolean(v), + }) as yup.ArraySchema, + descendants: yup.array(yup.string().required()).test({ + name: 'isDefined', + message: 'descendants must be defined', + test: v => Boolean(v), + }) as yup.ArraySchema, }) .required(), }); diff --git a/packages/catalog-model/src/kinds/UserEntityV1alpha1.ts b/packages/catalog-model/src/kinds/UserEntityV1alpha1.ts index 293f87b319..6086b3776e 100644 --- a/packages/catalog-model/src/kinds/UserEntityV1alpha1.ts +++ b/packages/catalog-model/src/kinds/UserEntityV1alpha1.ts @@ -37,11 +37,11 @@ const schema = yup.object>({ // element and there is no simple workaround -_- // the cast is there to convince typescript that the array itself is // required without using .required() - // memberOf: yup.array(yup.string().required()).test({ - // name: 'isDefined', - // message: 'memberOf must be defined', - // test: v => Boolean(v), - // }) as yup.ArraySchema, + memberOf: yup.array(yup.string().required()).test({ + name: 'isDefined', + message: 'memberOf must be defined', + test: v => Boolean(v), + }) as yup.ArraySchema, }) .required(), }); diff --git a/packages/catalog-model/src/kinds/index.ts b/packages/catalog-model/src/kinds/index.ts index 6df4f1212a..4a3faf977b 100644 --- a/packages/catalog-model/src/kinds/index.ts +++ b/packages/catalog-model/src/kinds/index.ts @@ -44,3 +44,4 @@ export type { UserEntityV1alpha1 as UserEntity, UserEntityV1alpha1, } from './UserEntityV1alpha1'; +export * from './relations'; diff --git a/packages/catalog-model/src/kinds/relations.ts b/packages/catalog-model/src/kinds/relations.ts new file mode 100644 index 0000000000..3964da99f9 --- /dev/null +++ b/packages/catalog-model/src/kinds/relations.ts @@ -0,0 +1,55 @@ +/* + * 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. + */ + +/* +Naming rules for relations in priority order: + +1. Use at most two words. One main verb and a specifier, e.g. "ownerOf" +2. Reading out " " should make sense in English. +3. Maintain symmetry between pairs, e.g. "ownedBy" and "ownerOf" rather than "owns". +*/ + +/** + * An ownership relation where the owner is usually an organizational + * entity (user or group), and the other entity can be anything. + */ +export const RELATION_OWNED_BY = 'ownedBy'; +export const RELATION_OWNER_OF = 'ownerOf'; + +/** + * A relation with an API entity, typically from a component or system + */ +export const RELATION_IMPLEMENTED_BY = 'implementedBy'; +export const RELATION_IMPLEMENTS = 'implements'; + +/** + * A relation denoting a dependency on another entity. + */ +export const RELATION_DEPENDS_ON = 'dependsOn'; +export const RELATION_DEPENDENCY_OF = 'dependencyOf'; + +/** + * A parent/child relation to build up a tree, used for example to describe + * the organizational structure between groups. + */ +export const RELATION_PARENT_OF = 'parentOf'; +export const RELATION_CHILD_OF = 'childOf'; + +/** + * A membership relation, typically for users in a group. + */ +export const RELATION_MEMBER_OF = 'memberOf'; +export const RELATION_HAS_MEMBER = 'hasMember'; diff --git a/plugins/catalog-backend/src/ingestion/processors/GroupPopulatorProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/OwnerRelationProcessor.ts similarity index 52% rename from plugins/catalog-backend/src/ingestion/processors/GroupPopulatorProcessor.ts rename to plugins/catalog-backend/src/ingestion/processors/OwnerRelationProcessor.ts index a1b0c6f15e..62a02207f1 100644 --- a/plugins/catalog-backend/src/ingestion/processors/GroupPopulatorProcessor.ts +++ b/plugins/catalog-backend/src/ingestion/processors/OwnerRelationProcessor.ts @@ -17,66 +17,61 @@ import { Entity, ENTITY_DEFAULT_NAMESPACE, - GroupEntity, LocationSpec, + parseEntityRef, + ApiEntityV1alpha1, + ComponentEntityV1alpha1, + RELATION_OWNED_BY, + RELATION_OWNER_OF, } from '@backstage/catalog-model'; import { CatalogProcessor, CatalogProcessorEmit } from './types'; import * as result from './results'; -export class GroupPopulatorProcessor implements CatalogProcessor { +const includedKinds = new Set(['api', 'component']); + +export class OwnerRelationProcessor implements CatalogProcessor { async postProcessEntity( entity: Entity, _location: LocationSpec, emit: CatalogProcessorEmit, ): Promise { - if (entity.kind.toLowerCase() !== 'group') { + if (!includedKinds.has(entity.kind.toLowerCase())) { return entity; } - const spec = entity.spec as GroupEntity['spec']; + const apiOrComponentEntity = entity as + | ApiEntityV1alpha1 + | ComponentEntityV1alpha1; - const { parent, children } = spec; - const self = { - kind: entity.kind, - name: entity.metadata.name, - namespace: entity.metadata.namespace ?? ENTITY_DEFAULT_NAMESPACE, - }; + const owner = apiOrComponentEntity.spec?.owner; + if (owner) { + const namespace = entity.metadata.namespace ?? ENTITY_DEFAULT_NAMESPACE; + + const selfRef = { + kind: entity.kind, + name: entity.metadata.name, + namespace, + }; + const ownerRef = parseEntityRef(owner, { + defaultKind: 'group', + defaultNamespace: namespace, + }); - if (parent) { emit( result.relation({ - type: 'parent', - source: self, - target: { ...self, name: parent }, + type: RELATION_OWNED_BY, + source: selfRef, + target: ownerRef, }), ); emit( result.relation({ - type: 'child', - source: { ...self, name: parent }, - target: self, + type: RELATION_OWNER_OF, + source: ownerRef, + target: selfRef, }), ); } - if (children) { - for (const child of children) { - emit( - result.relation({ - type: 'child', - source: self, - target: { ...self, name: child }, - }), - ); - emit( - result.relation({ - type: 'parent', - source: { ...self, name: child }, - target: self, - }), - ); - } - } - return entity; } } diff --git a/plugins/catalog-backend/src/ingestion/processors/index.ts b/plugins/catalog-backend/src/ingestion/processors/index.ts index 2a09247e45..92303f04a3 100644 --- a/plugins/catalog-backend/src/ingestion/processors/index.ts +++ b/plugins/catalog-backend/src/ingestion/processors/index.ts @@ -28,7 +28,7 @@ export { GithubOrgReaderProcessor } from './GithubOrgReaderProcessor'; export { GithubReaderProcessor } from './GithubReaderProcessor'; export { GitlabApiReaderProcessor } from './GitlabApiReaderProcessor'; export { GitlabReaderProcessor } from './GitlabReaderProcessor'; -export { GroupPopulatorProcessor } from './GroupPopulatorProcessor'; +export { OwnerRelationProcessor } from './OwnerRelationProcessor'; export { LocationRefProcessor } from './LocationEntityProcessor'; export { PlaceholderProcessor } from './PlaceholderProcessor'; export type { PlaceholderResolver } from './PlaceholderProcessor'; diff --git a/plugins/catalog-backend/src/service/CatalogBuilder.ts b/plugins/catalog-backend/src/service/CatalogBuilder.ts index 52f10232ce..4ec2a0834d 100644 --- a/plugins/catalog-backend/src/service/CatalogBuilder.ts +++ b/plugins/catalog-backend/src/service/CatalogBuilder.ts @@ -52,7 +52,7 @@ import { GithubReaderProcessor, GitlabApiReaderProcessor, GitlabReaderProcessor, - GroupPopulatorProcessor, + OwnerRelationProcessor, HigherOrderOperation, HigherOrderOperations, LocationReaders, @@ -335,7 +335,7 @@ export class CatalogBuilder { new YamlProcessor(), new CodeOwnersProcessor({ reader }), new LocationRefProcessor(), - new GroupPopulatorProcessor(), + new OwnerRelationProcessor(), new AnnotateLocationEntityProcessor(), ];