Add a managed-by-origin-location annotation

This commit is contained in:
Dominik Henneke
2021-01-19 14:05:52 +01:00
parent 342eccc25a
commit def2307f33
8 changed files with 139 additions and 11 deletions
@@ -78,13 +78,17 @@ export class LocationReaders implements LocationReader {
if (rulesEnforcer.isAllowed(item.entity, item.location)) {
const relations = Array<EntityRelationSpec>();
const entity = await this.handleEntity(item, emitResult => {
if (emitResult.type === 'relation') {
relations.push(emitResult.relation);
return;
}
emit(emitResult);
});
const entity = await this.handleEntity(
item,
emitResult => {
if (emitResult.type === 'relation') {
relations.push(emitResult.relation);
return;
}
emit(emitResult);
},
location,
);
if (entity) {
output.entities.push({
@@ -165,6 +169,7 @@ export class LocationReaders implements LocationReader {
private async handleEntity(
item: CatalogProcessorEntityResult,
emit: CatalogProcessorEmit,
originLocation: LocationSpec,
): Promise<Entity | undefined> {
const { processors, logger } = this.options;
@@ -185,6 +190,7 @@ export class LocationReaders implements LocationReader {
current,
item.location,
emit,
originLocation,
);
} catch (e) {
const message = `Processor ${processor.constructor.name} threw an error while preprocessing entity ${kind}:${namespace}/${name} at ${item.location.type} ${item.location.target}, ${e}`;
@@ -0,0 +1,62 @@
/*
* 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, LocationSpec } from '@backstage/catalog-model';
import { AnnotateLocationEntityProcessor } from './AnnotateLocationEntityProcessor';
describe('AnnotateLocationEntityProcessor', () => {
describe('preProcessEntity', () => {
it('adds annotations', async () => {
const entity: Entity = {
apiVersion: 'backstage.io/v1alpha1',
kind: 'Component',
metadata: {
name: 'my-component',
},
};
const location: LocationSpec = {
type: 'url',
target: 'my-location',
};
const originLocation: LocationSpec = {
type: 'url',
target: 'my-origin-location',
};
const processor = new AnnotateLocationEntityProcessor();
expect(
await processor.preProcessEntity(
entity,
location,
() => {},
originLocation,
),
).toEqual({
apiVersion: 'backstage.io/v1alpha1',
kind: 'Component',
metadata: {
name: 'my-component',
annotations: {
'backstage.io/managed-by-location': 'url:my-location',
'backstage.io/managed-by-origin-location': 'url:my-origin-location',
},
},
});
});
});
});
@@ -14,20 +14,28 @@
* limitations under the License.
*/
import { Entity, LocationSpec } from '@backstage/catalog-model';
import {
Entity,
LOCATION_ANNOTATION,
LocationSpec,
ORIGIN_LOCATION_ANNOTATION,
} from '@backstage/catalog-model';
import lodash from 'lodash';
import { CatalogProcessor } from './types';
import { CatalogProcessor, CatalogProcessorEmit } from './types';
export class AnnotateLocationEntityProcessor implements CatalogProcessor {
async preProcessEntity(
entity: Entity,
location: LocationSpec,
_: CatalogProcessorEmit,
originLocation: LocationSpec,
): Promise<Entity> {
return lodash.merge(
{
metadata: {
annotations: {
'backstage.io/managed-by-location': `${location.type}:${location.target}`,
[LOCATION_ANNOTATION]: `${location.type}:${location.target}`,
[ORIGIN_LOCATION_ANNOTATION]: `${originLocation.type}:${originLocation.target}`,
},
},
},
@@ -46,12 +46,16 @@ export type CatalogProcessor = {
* @param entity The (possibly partial) entity to process
* @param location The location that the entity came from
* @param emit A sink for auxiliary items resulting from the processing
* @param originLocation The location that the entity originally came from.
* While location resolves to the direct parent location, originLocation
* tells which location was used to start the ingestion loop.
* @returns The same entity or a modified version of it
*/
preProcessEntity?(
entity: Entity,
location: LocationSpec,
emit: CatalogProcessorEmit,
originLocation: LocationSpec,
): Promise<Entity>;
/**