relations wip
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
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
|
||||
@@ -69,7 +69,11 @@ describe('HigherOrderOperations', () => {
|
||||
};
|
||||
locationsCatalog.addLocation.mockImplementation(x => Promise.resolve(x));
|
||||
locationsCatalog.locations.mockResolvedValue([]);
|
||||
locationReader.read.mockResolvedValue({ entities: [], errors: [] });
|
||||
locationReader.read.mockResolvedValue({
|
||||
entities: [],
|
||||
errors: [],
|
||||
relations: [],
|
||||
});
|
||||
|
||||
const result = await higherOrderOperation.addLocation(spec);
|
||||
|
||||
@@ -109,7 +113,11 @@ describe('HigherOrderOperations', () => {
|
||||
data: location,
|
||||
},
|
||||
]);
|
||||
locationReader.read.mockResolvedValue({ entities: [], errors: [] });
|
||||
locationReader.read.mockResolvedValue({
|
||||
entities: [],
|
||||
errors: [],
|
||||
relations: [],
|
||||
});
|
||||
|
||||
const result = await higherOrderOperation.addLocation(spec);
|
||||
|
||||
@@ -138,6 +146,7 @@ describe('HigherOrderOperations', () => {
|
||||
locationReader.read.mockResolvedValue({
|
||||
entities: [{ entity, location }],
|
||||
errors: [{ error: new Error('abcd'), location }],
|
||||
relations: [],
|
||||
});
|
||||
|
||||
await expect(higherOrderOperation.addLocation(spec)).rejects.toThrow(
|
||||
@@ -186,6 +195,7 @@ describe('HigherOrderOperations', () => {
|
||||
locationReader.read.mockResolvedValue({
|
||||
entities: [{ entity: desc, location }],
|
||||
errors: [],
|
||||
relations: [],
|
||||
});
|
||||
entitiesCatalog.batchAddOrUpdateEntities.mockResolvedValue(undefined);
|
||||
|
||||
@@ -231,6 +241,7 @@ describe('HigherOrderOperations', () => {
|
||||
locationReader.read.mockResolvedValue({
|
||||
entities: [{ entity: desc, location }],
|
||||
errors: [],
|
||||
relations: [],
|
||||
});
|
||||
entitiesCatalog.entities.mockResolvedValue([]);
|
||||
entitiesCatalog.addEntities.mockResolvedValue(undefined);
|
||||
|
||||
@@ -61,7 +61,11 @@ export class LocationReaders implements LocationReader {
|
||||
async read(location: LocationSpec): Promise<ReadLocationResult> {
|
||||
const { rulesEnforcer, logger } = this.options;
|
||||
|
||||
const output: ReadLocationResult = { entities: [], errors: [] };
|
||||
const output: ReadLocationResult = {
|
||||
entities: [],
|
||||
errors: [],
|
||||
relations: [],
|
||||
};
|
||||
let items: CatalogProcessorResult[] = [result.location(location, false)];
|
||||
|
||||
for (let depth = 0; depth < MAX_DEPTH; ++depth) {
|
||||
@@ -96,6 +100,10 @@ export class LocationReaders implements LocationReader {
|
||||
location: item.location,
|
||||
error: item.error,
|
||||
});
|
||||
} else if (item.type === 'relation') {
|
||||
output.relations.push({
|
||||
relation: item.relation,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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 {
|
||||
Entity,
|
||||
ENTITY_DEFAULT_NAMESPACE,
|
||||
GroupEntity,
|
||||
LocationSpec,
|
||||
} from '@backstage/catalog-model';
|
||||
import { CatalogProcessor, CatalogProcessorEmit } from './types';
|
||||
import * as result from './results';
|
||||
|
||||
export class GroupPopulatorProcessor implements CatalogProcessor {
|
||||
async postProcessEntity(
|
||||
entity: Entity,
|
||||
_location: LocationSpec,
|
||||
emit: CatalogProcessorEmit,
|
||||
): Promise<Entity> {
|
||||
if (entity.kind.toLowerCase() !== 'group') {
|
||||
return entity;
|
||||
}
|
||||
const spec = entity.spec as GroupEntity['spec'];
|
||||
|
||||
const { parent, children } = spec;
|
||||
const self = {
|
||||
kind: entity.kind,
|
||||
name: entity.metadata.name,
|
||||
namespace: entity.metadata.namespace ?? ENTITY_DEFAULT_NAMESPACE,
|
||||
};
|
||||
|
||||
if (parent) {
|
||||
emit(
|
||||
result.relation({
|
||||
type: 'parent',
|
||||
source: self,
|
||||
target: { ...self, name: parent },
|
||||
}),
|
||||
);
|
||||
emit(
|
||||
result.relation({
|
||||
type: 'child',
|
||||
source: { ...self, name: parent },
|
||||
target: self,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ export { GithubOrgReaderProcessor } from './GithubOrgReaderProcessor';
|
||||
export { GithubReaderProcessor } from './GithubReaderProcessor';
|
||||
export { GitlabApiReaderProcessor } from './GitlabApiReaderProcessor';
|
||||
export { GitlabReaderProcessor } from './GitlabReaderProcessor';
|
||||
export { GroupPopulatorProcessor } from './GroupPopulatorProcessor';
|
||||
export { LocationRefProcessor } from './LocationEntityProcessor';
|
||||
export { PlaceholderProcessor } from './PlaceholderProcessor';
|
||||
export type { PlaceholderResolver } from './PlaceholderProcessor';
|
||||
|
||||
@@ -15,7 +15,11 @@
|
||||
*/
|
||||
|
||||
import { InputError, NotFoundError } from '@backstage/backend-common';
|
||||
import { Entity, LocationSpec } from '@backstage/catalog-model';
|
||||
import {
|
||||
Entity,
|
||||
EntityRelationSpec,
|
||||
LocationSpec,
|
||||
} from '@backstage/catalog-model';
|
||||
import { CatalogProcessorResult } from './types';
|
||||
|
||||
export function notFoundError(
|
||||
@@ -67,3 +71,7 @@ export function entity(
|
||||
): CatalogProcessorResult {
|
||||
return { type: 'entity', location: atLocation, entity: newEntity };
|
||||
}
|
||||
|
||||
export function relation(spec: EntityRelationSpec): CatalogProcessorResult {
|
||||
return { type: 'relation', relation: spec };
|
||||
}
|
||||
|
||||
@@ -14,7 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Entity, LocationSpec } from '@backstage/catalog-model';
|
||||
import {
|
||||
Entity,
|
||||
EntityRelationSpec,
|
||||
LocationSpec,
|
||||
} from '@backstage/catalog-model';
|
||||
|
||||
export type CatalogProcessor = {
|
||||
/**
|
||||
@@ -113,6 +117,11 @@ export type CatalogProcessorEntityResult = {
|
||||
location: LocationSpec;
|
||||
};
|
||||
|
||||
export type CatalogProcessorRelationResult = {
|
||||
type: 'relation';
|
||||
relation: EntityRelationSpec;
|
||||
};
|
||||
|
||||
export type CatalogProcessorErrorResult = {
|
||||
type: 'error';
|
||||
error: Error;
|
||||
@@ -123,4 +132,5 @@ export type CatalogProcessorResult =
|
||||
| CatalogProcessorLocationResult
|
||||
| CatalogProcessorDataResult
|
||||
| CatalogProcessorEntityResult
|
||||
| CatalogProcessorRelationResult
|
||||
| CatalogProcessorErrorResult;
|
||||
|
||||
@@ -14,7 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { Entity, Location, LocationSpec } from '@backstage/catalog-model';
|
||||
import type {
|
||||
Entity,
|
||||
EntityRelationSpec,
|
||||
Location,
|
||||
LocationSpec,
|
||||
} from '@backstage/catalog-model';
|
||||
|
||||
//
|
||||
// HigherOrderOperation
|
||||
@@ -47,6 +52,7 @@ export type LocationReader = {
|
||||
|
||||
export type ReadLocationResult = {
|
||||
entities: ReadLocationEntity[];
|
||||
relations: { relation: EntityRelationSpec }[];
|
||||
errors: ReadLocationError[];
|
||||
};
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ import {
|
||||
GithubReaderProcessor,
|
||||
GitlabApiReaderProcessor,
|
||||
GitlabReaderProcessor,
|
||||
GroupPopulatorProcessor,
|
||||
HigherOrderOperation,
|
||||
HigherOrderOperations,
|
||||
LocationReaders,
|
||||
@@ -334,6 +335,7 @@ export class CatalogBuilder {
|
||||
new YamlProcessor(),
|
||||
new CodeOwnersProcessor({ reader }),
|
||||
new LocationRefProcessor(),
|
||||
new GroupPopulatorProcessor(),
|
||||
new AnnotateLocationEntityProcessor(),
|
||||
];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user