catalog-model: Remove deprecations

Signed-off-by: Johan Haals <johan.haals@gmail.com>
This commit is contained in:
Johan Haals
2022-03-01 15:50:03 +01:00
parent d9e9b23576
commit ac7b1161a6
14 changed files with 26 additions and 939 deletions
-86
View File
@@ -4,8 +4,6 @@
```ts
import { JsonObject } from '@backstage/types';
import { JSONSchema7 } from 'json-schema';
import { JsonValue } from '@backstage/types';
import { SerializedError } from '@backstage/errors';
// @alpha
@@ -66,23 +64,6 @@ export class CommonValidatorFunctions {
static isValidUrl(value: unknown): boolean;
}
// @public @deprecated
export function compareEntityToRef(
entity: Entity,
ref:
| string
| {
kind?: string;
namespace?: string;
name: string;
}
| EntityName,
context?: {
defaultKind?: string;
defaultNamespace?: string;
},
): boolean;
// @public
interface ComponentEntityV1alpha1 extends Entity {
// (undocumented)
@@ -134,9 +115,6 @@ export { DomainEntityV1alpha1 };
// @public
export const domainEntityV1alpha1Validator: KindValidator;
// @public @deprecated
export const EDIT_URL_ANNOTATION = 'backstage.io/edit-url';
// @public
export type Entity = {
apiVersion: string;
@@ -146,16 +124,6 @@ export type Entity = {
relations?: EntityRelation[];
};
// @public @deprecated
export const ENTITY_DEFAULT_NAMESPACE = 'default';
// @public @deprecated
export const ENTITY_META_GENERATED_FIELDS: readonly [
'uid',
'etag',
'generation',
];
// @public
export type EntityEnvelope = {
apiVersion: string;
@@ -171,9 +139,6 @@ export function entityEnvelopeSchemaValidator<
T extends EntityEnvelope = EntityEnvelope,
>(schema?: unknown): (data: unknown) => T;
// @public @deprecated
export function entityHasChanges(previous: Entity, next: Entity): boolean;
// @public
export function entityKindSchemaValidator<T extends Entity>(
schema: unknown,
@@ -228,12 +193,6 @@ export type EntityRef =
name: string;
};
// @public @deprecated
export type EntityRefContext = {
defaultKind?: string;
defaultNamespace?: string;
};
// @public
export type EntityRelation = {
type: string;
@@ -269,15 +228,6 @@ export class FieldFormatEntityPolicy implements EntityPolicy {
enforce(entity: Entity): Promise<Entity>;
}
// @public @deprecated
export function generateEntityEtag(): string;
// @public @deprecated
export function generateEntityUid(): string;
// @public @deprecated
export function generateUpdatedEntity(previous: Entity, next: Entity): Entity;
// @public
export function getEntityName(entity: Entity): EntityName;
@@ -312,11 +262,6 @@ export { GroupEntityV1alpha1 };
// @public
export const groupEntityV1alpha1Validator: KindValidator;
// @public @deprecated
export type JSONSchema = JSONSchema7 & {
[key in string]?: JsonValue;
};
// @public
export type KindValidator = {
check(entity: Entity): Promise<boolean>;
@@ -342,15 +287,6 @@ export class KubernetesValidatorFunctions {
static isValidObjectName(value: unknown): boolean;
}
// @public @deprecated
type Location_2 = {
id: string;
} & LocationSpec;
export { Location_2 as Location };
// @public @deprecated
export const LOCATION_ANNOTATION = 'backstage.io/managed-by-location';
// @public
interface LocationEntityV1alpha1 extends Entity {
// (undocumented)
@@ -388,10 +324,6 @@ export class NoForeignRootFieldsEntityPolicy implements EntityPolicy {
enforce(entity: Entity): Promise<Entity>;
}
// @public @deprecated
export const ORIGIN_LOCATION_ANNOTATION =
'backstage.io/managed-by-origin-location';
// @public @deprecated
export function parseEntityName(
ref:
@@ -428,12 +360,6 @@ export function parseLocationRef(ref: string): {
target: string;
};
// @public @deprecated
export function parseLocationReference(ref: string): {
type: string;
target: string;
};
// @public
export const RELATION_API_CONSUMED_BY = 'apiConsumedBy';
@@ -503,9 +429,6 @@ export class SchemaValidEntityPolicy implements EntityPolicy {
enforce(entity: Entity): Promise<Entity>;
}
// @public @deprecated
export const SOURCE_LOCATION_ANNOTATION = 'backstage.io/source-location';
// @public
export function stringifyEntityRef(
ref:
@@ -523,12 +446,6 @@ export function stringifyLocationRef(ref: {
target: string;
}): string;
// @public @deprecated
export function stringifyLocationReference(ref: {
type: string;
target: string;
}): string;
// @public
interface SystemEntityV1alpha1 extends Entity {
// (undocumented)
@@ -581,7 +498,4 @@ export type Validators = {
isValidAnnotationValue(value: unknown): boolean;
isValidTag(value: unknown): boolean;
};
// @public @deprecated
export const VIEW_URL_ANNOTATION = 'backstage.io/view-url';
```
@@ -14,14 +14,6 @@
* limitations under the License.
*/
/**
* The namespace that entities without an explicit namespace fall into.
*
* @public
* @deprecated use {@link DEFAULT_NAMESPACE} instead.
*/
export const ENTITY_DEFAULT_NAMESPACE = 'default';
/**
* The namespace that entities without an explicit namespace fall into.
*
@@ -29,34 +21,6 @@ export const ENTITY_DEFAULT_NAMESPACE = 'default';
*/
export const DEFAULT_NAMESPACE = 'default';
/**
* The keys of EntityMeta that are auto-generated.
*
* @public
* @deprecated will be removed in a future release.
*/
export const ENTITY_META_GENERATED_FIELDS = [
'uid',
'etag',
'generation',
] as const;
/**
* Annotation for linking to entity page from catalog pages.
*
* @public
* @deprecated use {@link ANNOTATION_VIEW_URL} instead.
*/
export const VIEW_URL_ANNOTATION = 'backstage.io/view-url';
/**
* Annotation for linking to entity edit page from catalog pages.
*
* @public
* @deprecated use {@link ANNOTATION_EDIT_URL} instead.
*/
export const EDIT_URL_ANNOTATION = 'backstage.io/edit-url';
/**
* Annotation for linking to entity page from catalog pages.
*
@@ -15,11 +15,7 @@
*/
export {
EDIT_URL_ANNOTATION,
ENTITY_DEFAULT_NAMESPACE,
DEFAULT_NAMESPACE,
ENTITY_META_GENERATED_FIELDS,
VIEW_URL_ANNOTATION,
ANNOTATION_EDIT_URL,
ANNOTATION_VIEW_URL,
} from './constants';
@@ -38,16 +34,8 @@ export type {
} from './EntityStatus';
export * from './policies';
export {
compareEntityToRef,
getEntityName,
parseEntityName,
parseEntityRef,
stringifyEntityRef,
} from './ref';
export type { EntityRefContext } from './ref';
export {
entityHasChanges,
generateEntityEtag,
generateEntityUid,
generateUpdatedEntity,
} from './util';
+1 -318
View File
@@ -15,8 +15,7 @@
*/
import { DEFAULT_NAMESPACE } from './constants';
import { Entity } from './Entity';
import { compareEntityToRef, parseEntityName, parseEntityRef } from './ref';
import { parseEntityName, parseEntityRef } from './ref';
describe('ref', () => {
describe('parseEntityName', () => {
@@ -313,320 +312,4 @@ describe('ref', () => {
).toThrow(/namespace/);
});
});
describe('compareEntityToRef', () => {
const entityWithNamespace: Entity = {
apiVersion: 'a',
kind: 'K',
metadata: {
name: 'n',
namespace: 'ns',
},
};
const entityWithoutNamespace: Entity = {
apiVersion: 'a',
kind: 'K',
metadata: {
name: 'n',
},
};
it('handles matching string refs', () => {
expect(compareEntityToRef(entityWithNamespace, 'K:ns/n')).toBe(true);
expect(compareEntityToRef(entityWithNamespace, 'k:nS/N')).toBe(true);
expect(
compareEntityToRef(entityWithNamespace, 'K:n', {
defaultNamespace: 'ns',
}),
).toBe(true);
expect(
compareEntityToRef(entityWithNamespace, 'K:n', {
defaultNamespace: 'Ns',
}),
).toBe(true);
expect(
compareEntityToRef(entityWithNamespace, 'ns/n', { defaultKind: 'K' }),
).toBe(true);
expect(
compareEntityToRef(entityWithNamespace, 'n', {
defaultKind: 'K',
defaultNamespace: 'ns',
}),
).toBe(true);
expect(
compareEntityToRef(entityWithNamespace, 'N', {
defaultKind: 'k',
defaultNamespace: 'nS',
}),
).toBe(true);
expect(compareEntityToRef(entityWithoutNamespace, 'K:default/n')).toBe(
true,
);
expect(compareEntityToRef(entityWithoutNamespace, 'K:deFault/n')).toBe(
true,
);
expect(
compareEntityToRef(entityWithoutNamespace, 'K:n', {
defaultNamespace: 'default',
}),
).toBe(true);
expect(
compareEntityToRef(entityWithoutNamespace, 'K:n', {
defaultNamespace: 'deFault',
}),
).toBe(true);
expect(compareEntityToRef(entityWithoutNamespace, 'K:default/n')).toBe(
true,
);
expect(compareEntityToRef(entityWithoutNamespace, 'K:n')).toBe(true);
expect(
compareEntityToRef(entityWithoutNamespace, 'default/n', {
defaultKind: 'K',
}),
).toBe(true);
expect(
compareEntityToRef(entityWithoutNamespace, 'n', {
defaultKind: 'K',
defaultNamespace: 'default',
}),
).toBe(true);
expect(
compareEntityToRef(entityWithoutNamespace, 'n', {
defaultKind: 'K',
}),
).toBe(true);
});
it('handles mismatching string refs', () => {
expect(compareEntityToRef(entityWithNamespace, 'X:ns/n')).toBe(false);
expect(
compareEntityToRef(entityWithoutNamespace, 'ns/n', {
defaultKind: 'X',
}),
).toBe(false);
expect(compareEntityToRef(entityWithNamespace, 'K:xx/n')).toBe(false);
expect(
compareEntityToRef(entityWithoutNamespace, 'K:n', {
defaultNamespace: 'xx',
}),
).toBe(false);
expect(compareEntityToRef(entityWithNamespace, 'K:ns/x')).toBe(false);
expect(
compareEntityToRef(entityWithoutNamespace, 'x', {
defaultKind: 'K',
defaultNamespace: 'ns',
}),
).toBe(false);
});
it('handles matching compound refs', () => {
expect(
compareEntityToRef(entityWithNamespace, {
kind: 'K',
namespace: 'ns',
name: 'n',
}),
).toBe(true);
expect(
compareEntityToRef(entityWithNamespace, {
kind: 'k',
namespace: 'Ns',
name: 'N',
}),
).toBe(true);
expect(
compareEntityToRef(
entityWithNamespace,
{ kind: 'K', name: 'n' },
{
defaultNamespace: 'ns',
},
),
).toBe(true);
expect(
compareEntityToRef(
entityWithNamespace,
{ namespace: 'ns', name: 'n' },
{ defaultKind: 'K' },
),
).toBe(true);
expect(
compareEntityToRef(entityWithNamespace, 'n', {
defaultKind: 'K',
defaultNamespace: 'ns',
}),
).toBe(true);
expect(
compareEntityToRef(entityWithNamespace, 'N', {
defaultKind: 'k',
defaultNamespace: 'nS',
}),
).toBe(true);
expect(
compareEntityToRef(entityWithoutNamespace, {
kind: 'K',
namespace: 'default',
name: 'n',
}),
).toBe(true);
expect(
compareEntityToRef(entityWithoutNamespace, {
kind: 'k',
namespace: 'deFault',
name: 'N',
}),
).toBe(true);
expect(
compareEntityToRef(
entityWithoutNamespace,
{ kind: 'K', name: 'n' },
{
defaultNamespace: 'default',
},
),
).toBe(true);
expect(
compareEntityToRef(entityWithoutNamespace, { kind: 'K', name: 'n' }),
).toBe(true);
expect(
compareEntityToRef(
entityWithoutNamespace,
{ namespace: 'default', name: 'n' },
{
defaultKind: 'K',
},
),
).toBe(true);
expect(
compareEntityToRef(
entityWithoutNamespace,
{ name: 'n' },
{
defaultKind: 'K',
defaultNamespace: 'default',
},
),
).toBe(true);
expect(
compareEntityToRef(
entityWithoutNamespace,
{ name: 'N' },
{
defaultKind: 'k',
defaultNamespace: 'defAult',
},
),
).toBe(true);
expect(
compareEntityToRef(
entityWithoutNamespace,
{ name: 'n' },
{
defaultKind: 'K',
},
),
).toBe(true);
});
it('handles mismatching compound refs', () => {
expect(
compareEntityToRef(entityWithNamespace, {
kind: 'X',
namespace: 'ns',
name: 'n',
}),
).toBe(false);
expect(
compareEntityToRef(
entityWithNamespace,
{
namespace: 'ns',
name: 'n',
},
{ defaultKind: 'X' },
),
).toBe(false);
expect(
compareEntityToRef(entityWithoutNamespace, {
kind: 'X',
namespace: 'default',
name: 'n',
}),
).toBe(false);
expect(
compareEntityToRef(
entityWithoutNamespace,
{
namespace: 'default',
name: 'n',
},
{ defaultKind: 'X' },
),
).toBe(false);
expect(
compareEntityToRef(entityWithNamespace, {
kind: 'K',
namespace: 'xx',
name: 'n',
}),
).toBe(false);
expect(
compareEntityToRef(
entityWithNamespace,
{
kind: 'K',
name: 'n',
},
{ defaultNamespace: 'xx' },
),
).toBe(false);
expect(
compareEntityToRef(entityWithoutNamespace, {
kind: 'K',
namespace: 'xx',
name: 'n',
}),
).toBe(false);
expect(
compareEntityToRef(
entityWithoutNamespace,
{
kind: 'K',
name: 'n',
},
{ defaultNamespace: 'xx' },
),
).toBe(false);
expect(
compareEntityToRef(entityWithNamespace, {
kind: 'K',
namespace: 'ns',
name: 'x',
}),
).toBe(false);
expect(
compareEntityToRef(entityWithoutNamespace, {
kind: 'K',
namespace: 'default',
name: 'x',
}),
).toBe(false);
expect(
compareEntityToRef(
entityWithoutNamespace,
{
kind: 'K',
name: 'x',
},
{ defaultNamespace: 'default' },
),
).toBe(false);
});
});
});
-77
View File
@@ -53,19 +53,6 @@ export function getEntityName(entity: Entity): EntityName {
};
}
/**
* The context of defaults that entity reference parsing happens within.
*
* @public
* @deprecated type inlined, will be removed in a future release.
*/
export type EntityRefContext = {
/** The default kind, if none is given in the reference */
defaultKind?: string;
/** The default namespace, if none is given in the reference */
defaultNamespace?: string;
};
/**
* Parses an entity reference, either on string or compound form, and always
* returns a complete entity name including kind, namespace and name.
@@ -203,67 +190,3 @@ export function stringifyEntityRef(
'en-US',
)}/${name.toLocaleLowerCase('en-US')}`;
}
/**
* Compares an entity to either a string reference or a compound reference.
*
* @remarks
*
* The comparison is case insensitive, and all of kind, namespace, and name
* must match (after applying the optional context to the ref).
*
* @public
* @param entity - The entity to match
* @param ref - A string or compound entity ref
* @param context - An optional context of default kind and namespace, that apply
* to the ref if given
* @returns True if matching, false otherwise
* @deprecated compare using stringifyEntityRef instead.
*/
export function compareEntityToRef(
entity: Entity,
ref:
| string
| { kind?: string; namespace?: string; name: string }
| EntityName,
context?: {
/** The default kind, if none is given in the reference */
defaultKind?: string;
/** The default namespace, if none is given in the reference */
defaultNamespace?: string;
},
): boolean {
const entityKind = entity.kind;
const entityNamespace = entity.metadata.namespace || DEFAULT_NAMESPACE;
const entityName = entity.metadata.name;
let refKind: string | undefined;
let refNamespace: string | undefined;
let refName: string;
if (typeof ref === 'string') {
const parsed = parseRefString(ref);
refKind = parsed.kind || context?.defaultKind;
refNamespace =
parsed.namespace || context?.defaultNamespace || DEFAULT_NAMESPACE;
refName = parsed.name;
} else {
refKind = ref.kind || context?.defaultKind;
refNamespace =
ref.namespace || context?.defaultNamespace || DEFAULT_NAMESPACE;
refName = ref.name;
}
if (!refKind || !refNamespace) {
throw new Error(
`Entity reference or context did not contain kind and namespace`,
);
}
return (
entityKind.toLocaleLowerCase('en-US') ===
refKind.toLocaleLowerCase('en-US') &&
entityNamespace.toLocaleLowerCase('en-US') ===
refNamespace.toLocaleLowerCase('en-US') &&
entityName.toLocaleLowerCase('en-US') === refName.toLocaleLowerCase('en-US')
);
}
@@ -1,198 +0,0 @@
/*
* Copyright 2020 The Backstage Authors
*
* 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 lodash from 'lodash';
import {
generateEntityEtag,
generateEntityUid,
entityHasChanges,
generateUpdatedEntity,
} from './util';
import { Entity } from './Entity';
describe('util', () => {
describe('generateEntityUid', () => {
it('generates randomness', () => {
expect(generateEntityUid()).not.toEqual('');
expect(generateEntityUid()).not.toEqual(generateEntityUid());
});
});
describe('generateEntityEtag', () => {
it('generates randomness', () => {
expect(generateEntityEtag()).not.toEqual('');
expect(generateEntityEtag()).not.toEqual(generateEntityEtag());
});
});
describe('entityHasChanges', () => {
let a: Entity;
beforeEach(() => {
a = {
apiVersion: 'backstage.io/v1alpha1',
kind: 'Component',
metadata: {
name: 'name',
custom: 'custom',
labels: {
labelKey: 'labelValue',
},
annotations: {
annotationKey: 'annotationValue',
},
},
spec: {
a: 'a',
},
};
});
it('happy path: clone has no changes', () => {
const b = lodash.cloneDeep(a);
expect(entityHasChanges(a, b)).toBe(false);
});
it('detects root field changes', () => {
let b: any = lodash.cloneDeep(a);
b.apiVersion += 'a';
expect(entityHasChanges(a, b)).toBe(true);
b = lodash.cloneDeep(a);
delete b.apiVersion;
expect(entityHasChanges(a, b)).toBe(true);
b = lodash.cloneDeep(a);
b.kind += 'a';
expect(entityHasChanges(a, b)).toBe(true);
b = lodash.cloneDeep(a);
delete b.kind;
expect(entityHasChanges(a, b)).toBe(true);
});
it('detects metadata changes', () => {
let b: any = lodash.cloneDeep(a);
b.metadata.name += 'a';
expect(entityHasChanges(a, b)).toBe(true);
b = lodash.cloneDeep(a);
delete b.metadata.custom;
expect(entityHasChanges(a, b)).toBe(true);
b = lodash.cloneDeep(a);
delete b.metadata.custom;
expect(entityHasChanges(a, b)).toBe(true);
b = lodash.cloneDeep(a);
b.metadata.labels.n = 'n';
expect(entityHasChanges(a, b)).toBe(true);
b = lodash.cloneDeep(a);
b.metadata.labels.labelKey += 'a';
expect(entityHasChanges(a, b)).toBe(true);
b = lodash.cloneDeep(a);
b.metadata.annotations.annotationKey += 'a';
expect(entityHasChanges(a, b)).toBe(true);
b = lodash.cloneDeep(a);
delete b.metadata.annotations.annotationKey;
expect(entityHasChanges(a, b)).toBe(true);
});
it('detects spec changes', () => {
let b: any = lodash.cloneDeep(a);
b.spec.a += 'a';
expect(entityHasChanges(a, b)).toBe(true);
b = lodash.cloneDeep(a);
delete b.spec.a;
expect(entityHasChanges(a, b)).toBe(true);
b = lodash.cloneDeep(a);
b.spec.n = 'n';
expect(entityHasChanges(a, b)).toBe(true);
});
});
describe('generateUpdatedEntity', () => {
let a: Entity;
let b: any;
beforeEach(() => {
a = {
apiVersion: 'backstage.io/v1alpha1',
kind: 'Component',
metadata: {
uid: 'da921f56-f655-4e6e-9b8b-bb19a57818d8',
etag: 'NzY5NDA5NzQtYmEwNC00MDY0LWFiYmItNTYxYzQxM2JhZDcx',
generation: 2,
name: 'name',
custom: 'custom',
labels: {
labelKey: 'labelValue',
},
annotations: {
annotationKey: 'annotationValue',
},
},
spec: {
a: 'a',
},
};
b = lodash.cloneDeep(a);
delete b.metadata.uid;
delete b.metadata.etag;
delete b.metadata.generation;
});
it('happy path: running on itself leaves it unchanged', () => {
const result = generateUpdatedEntity(a, b);
expect(result).toEqual(a);
});
it('bumps etag and generation when spec is changed', () => {
b.spec.a += 'a';
const result = generateUpdatedEntity(a, b);
expect(result.metadata.uid).toEqual(a.metadata.uid);
expect(result.metadata.etag).not.toEqual(a.metadata.etag);
expect(result.metadata.generation).toEqual(a.metadata.generation! + 1);
expect(result.spec).toEqual({ a: 'aa' });
});
it('bumps only etag when other things than spec are changed', () => {
b.metadata.n = 'n';
const result = generateUpdatedEntity(a, b);
expect(result.metadata.uid).toEqual(a.metadata.uid);
expect(result.metadata.etag).not.toEqual(a.metadata.etag);
expect(result.metadata.generation).toEqual(a.metadata.generation);
expect(result.metadata.n).toEqual('n');
});
it('retains new annotations', () => {
b.metadata.annotations.annotationKey = 'changedValue';
b.metadata.annotations.newKey = 'newValue';
const result = generateUpdatedEntity(a, b);
expect(result.metadata.uid).toEqual(a.metadata.uid);
expect(result.metadata.etag).not.toEqual(a.metadata.etag);
expect(result.metadata.generation).toEqual(a.metadata.generation);
expect(result.metadata.annotations).toEqual({
annotationKey: 'changedValue',
newKey: 'newValue',
});
});
it('retains old annotations', () => {
b.metadata.annotations.newKey = 'newValue';
const result = generateUpdatedEntity(a, b);
expect(result.metadata.uid).toEqual(a.metadata.uid);
expect(result.metadata.etag).not.toEqual(a.metadata.etag);
expect(result.metadata.generation).toEqual(a.metadata.generation);
expect(result.metadata.annotations).toEqual({
annotationKey: 'annotationValue',
newKey: 'newValue',
});
});
});
});
-133
View File
@@ -1,133 +0,0 @@
/*
* Copyright 2020 The Backstage Authors
*
* 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 lodash from 'lodash';
import { v4 as uuidv4 } from 'uuid';
import { Entity, AlphaEntity } from './Entity';
/**
* Generates a new random UID for an entity.
*
* @public
* @returns A string with enough randomness to uniquely identify an entity
* @deprecated use `uuidv4()` instead.
*/
export function generateEntityUid(): string {
return uuidv4();
}
/**
* Generates a new random Etag for an entity.
*
* @public
* @returns A string with enough randomness to uniquely identify an entity
* revision
* @deprecated will be removed in a future release.
*/
export function generateEntityEtag(): string {
return Buffer.from(uuidv4(), 'utf8').toString('base64').replace(/[^\w]/g, '');
}
/**
* Checks whether there are any significant changes going from the previous to
* the next version of this entity.
*
* @remarks
*
* Significance, in this case, means that we do not compare generated fields
* such as uid, etag and generation.
*
* Note that this comparison does NOT take status, relations or similar into
* account. It only compares the actual input entity data, i.e. metadata and
* spec.
*
* @public
* @param previous - The old state of the entity
* @param next - The new state of the entity
* @deprecated will be removed in a future release.
*/
export function entityHasChanges(previous: Entity, next: Entity): boolean {
const e1 = lodash.cloneDeep(previous);
const e2 = lodash.cloneDeep(next);
if (!e1.metadata.labels) {
e1.metadata.labels = {};
}
if (!e2.metadata.labels) {
e2.metadata.labels = {};
}
if (!e1.metadata.annotations) {
e1.metadata.annotations = {};
}
if (!e2.metadata.annotations) {
e2.metadata.annotations = {};
}
if (!e1.metadata.tags) {
e1.metadata.tags = [];
}
if (!e2.metadata.tags) {
e2.metadata.tags = [];
}
// Remove generated fields
delete e1.metadata.uid;
delete e1.metadata.etag;
delete e1.metadata.generation;
delete e2.metadata.uid;
delete e2.metadata.etag;
delete e2.metadata.generation;
// Remove things that we explicitly do not compare
delete e1.relations;
delete (e1 as AlphaEntity).status;
delete e2.relations;
delete (e2 as AlphaEntity).status;
return !lodash.isEqual(e1, e2);
}
/**
* Takes an old revision of an entity and a new desired state, and merges
* them into a complete new state.
*
* @remarks
*
* The previous revision is expected to be a complete model loaded from the
* catalog, including the uid, etag and generation fields.
*
* @public
* @param previous - The old state of the entity
* @param next - The new state of the entity
* @returns An entity with the merged state of both
* @deprecated will be removed in a future release.
*/
export function generateUpdatedEntity(previous: Entity, next: Entity): Entity {
const { uid, etag, generation } = previous.metadata;
if (!uid || !etag || !generation) {
throw new Error('Previous entity must have uid, etag and generation');
}
const result = lodash.cloneDeep(next);
// Generated fields are copied and updated
const bumpEtag = entityHasChanges(previous, result);
const bumpGeneration = !lodash.isEqual(previous.spec, result.spec);
result.metadata.uid = uid;
result.metadata.etag = bumpEtag ? generateEntityEtag() : etag;
result.metadata.generation = bumpGeneration ? generation + 1 : generation;
return result;
}
+1 -1
View File
@@ -24,5 +24,5 @@ export * from './entity';
export { EntityPolicies } from './EntityPolicies';
export * from './kinds';
export * from './location';
export type { EntityName, EntityRef, JSONSchema } from './types';
export type { EntityName, EntityRef } from './types';
export * from './validation';
@@ -14,30 +14,6 @@
* limitations under the License.
*/
/**
* Constant storing location annotation.
*
* @public
* @deprecated use {@link ANNOTATION_LOCATION} instead.
* */
export const LOCATION_ANNOTATION = 'backstage.io/managed-by-location';
/**
* Constant storing origin location annotation
*
* @public
* @deprecated use {@link ANNOTATION_ORIGIN_LOCATION} instead.
*/
export const ORIGIN_LOCATION_ANNOTATION =
'backstage.io/managed-by-origin-location';
/**
* Contant storing source location annotation
*
* @public
* @deprecated use {@link ANNOTATION_SOURCE_LOCATION} instead.
* */
export const SOURCE_LOCATION_ANNOTATION = 'backstage.io/source-location';
/**
* Constant storing location annotation.
*
@@ -18,18 +18,6 @@ import { ANNOTATION_SOURCE_LOCATION } from '.';
import { Entity, stringifyEntityRef } from '../entity';
import { ANNOTATION_LOCATION } from './annotation';
/**
* Parses a string form location reference.
*
* @public
* @param ref - A string-form location reference, e.g. `'url:https://host'`
* @returns A location reference, e.g. `{ type: 'url', target: 'https://host' }`
* @deprecated use {@link parseLocationRef} instead
*/
export function parseLocationReference(ref: string) {
return parseLocationRef(ref);
}
/**
* Parses a string form location reference.
*
@@ -72,21 +60,6 @@ export function parseLocationRef(ref: string): {
return { type, target };
}
/**
* Turns a location reference into its string form.
*
* @public
* @param ref - A location reference, e.g. `{ type: 'url', target: 'https://host' }`
* @returns A string-form location reference, e.g. `'url:https://host'`
* @deprecated use {@link stringifyLocationRef} instead
*/
export function stringifyLocationReference(ref: {
type: string;
target: string;
}): string {
return stringifyLocationRef(ref);
}
/**
* Turns a location ref into its string form.
*
+1 -6
View File
@@ -18,15 +18,10 @@ export {
ANNOTATION_LOCATION,
ANNOTATION_ORIGIN_LOCATION,
ANNOTATION_SOURCE_LOCATION,
LOCATION_ANNOTATION,
ORIGIN_LOCATION_ANNOTATION,
SOURCE_LOCATION_ANNOTATION,
} from './annotation';
export {
getEntitySourceLocation,
parseLocationRef,
parseLocationReference,
stringifyLocationRef,
stringifyLocationReference,
} from './helpers';
export type { Location, LocationSpec } from './types';
export type { LocationSpec } from './types';
@@ -31,13 +31,3 @@ export type LocationSpec = {
target: string;
presence?: 'optional' | 'required';
};
/**
* Entity location for a specific entity.
*
* @public
* @deprecated import from {@link @backstage/catalog-client#Location} instead.
*/
export type Location = {
id: string;
} & LocationSpec;
-11
View File
@@ -14,17 +14,6 @@
* limitations under the License.
*/
import { JsonValue } from '@backstage/types';
import { JSONSchema7 } from 'json-schema';
/**
* JSONSchema extendable by arbitrary JSON attributes
*
* @public
* @deprecated use JSONSchema7 from the json-schema package instead.
*/
export type JSONSchema = JSONSchema7 & { [key in string]?: JsonValue };
/**
* A complete entity name, with the full kind-namespace-name triplet.
*