catalog-model: rename parse/stringifyLocationRef

Signed-off-by: Fredrik Adelöw <freben@gmail.com>
This commit is contained in:
Fredrik Adelöw
2022-02-11 17:11:10 +01:00
parent d3292ab1ba
commit 216725b434
17 changed files with 139 additions and 73 deletions
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/catalog-model': patch
---
Deprecated `parseLocationReference` and `stringifyLocationReference`,
introducing `parseLocationRef` and `stringifyLocationRef` in their place.
+11
View File
@@ -0,0 +1,11 @@
---
'@backstage/catalog-client': patch
'@backstage/techdocs-common': patch
'@backstage/plugin-catalog-backend': patch
'@backstage/plugin-catalog-react': patch
'@backstage/plugin-github-deployments': patch
'@backstage/plugin-scaffolder-backend': patch
'@backstage/plugin-todo-backend': patch
---
Updated to use new names for `parseLocationRef` and `stringifyLocationRef`
+3 -3
View File
@@ -22,7 +22,7 @@ import {
ORIGIN_LOCATION_ANNOTATION,
parseEntityRef,
stringifyEntityRef,
stringifyLocationReference,
stringifyLocationRef,
} from '@backstage/catalog-model';
import { ResponseError } from '@backstage/errors';
import crossFetch from 'cross-fetch';
@@ -310,7 +310,7 @@ export class CatalogClient implements CatalogApi {
);
return all
.map(r => r.data)
.find(l => locationCompound === stringifyLocationReference(l));
.find(l => locationCompound === stringifyLocationRef(l));
}
/**
@@ -338,7 +338,7 @@ export class CatalogClient implements CatalogApi {
);
return all
.map(r => r.data)
.find(l => locationCompound === stringifyLocationReference(l));
.find(l => locationCompound === stringifyLocationRef(l));
}
/**
+12
View File
@@ -409,6 +409,12 @@ export function parseEntityRef(
};
// @public
export function parseLocationRef(ref: string): {
type: string;
target: string;
};
// @public @deprecated
export function parseLocationReference(ref: string): {
type: string;
target: string;
@@ -509,6 +515,12 @@ export function stringifyEntityRef(
): string;
// @public
export function stringifyLocationRef(ref: {
type: string;
target: string;
}): string;
// @public @deprecated
export function stringifyLocationReference(ref: {
type: string;
target: string;
@@ -16,47 +16,47 @@
import {
getEntitySourceLocation,
parseLocationReference,
stringifyLocationReference,
parseLocationRef,
stringifyLocationRef,
} from './helpers';
describe('parseLocationReference', () => {
describe('parseLocationRef', () => {
it('works for the simple case', () => {
expect(parseLocationReference('url:https://www.google.com')).toEqual({
expect(parseLocationRef('url:https://www.google.com')).toEqual({
type: 'url',
target: 'https://www.google.com',
});
});
it('rejects faulty inputs', () => {
expect(() => parseLocationReference(7 as any)).toThrow(
"Unable to parse location reference '7', unexpected argument number",
expect(() => parseLocationRef(7 as any)).toThrow(
"Unable to parse location ref '7', unexpected argument number",
);
expect(() => parseLocationReference('')).toThrow(
"Unable to parse location reference '', expected '<type>:<target>', e.g. 'url:https://host/path'",
expect(() => parseLocationRef('')).toThrow(
"Unable to parse location ref '', expected '<type>:<target>', e.g. 'url:https://host/path'",
);
expect(() => parseLocationReference('hello')).toThrow(
"Unable to parse location reference 'hello', expected '<type>:<target>', e.g. 'url:https://host/path'",
expect(() => parseLocationRef('hello')).toThrow(
"Unable to parse location ref 'hello', expected '<type>:<target>', e.g. 'url:https://host/path'",
);
expect(() => parseLocationReference(':hello')).toThrow(
"Unable to parse location reference ':hello', expected '<type>:<target>', e.g. 'url:https://host/path'",
expect(() => parseLocationRef(':hello')).toThrow(
"Unable to parse location ref ':hello', expected '<type>:<target>', e.g. 'url:https://host/path'",
);
expect(() => parseLocationReference('hello:')).toThrow(
"Unable to parse location reference 'hello:', expected '<type>:<target>', e.g. 'url:https://host/path'",
expect(() => parseLocationRef('hello:')).toThrow(
"Unable to parse location ref 'hello:', expected '<type>:<target>', e.g. 'url:https://host/path'",
);
expect(() => parseLocationReference('http://blah')).toThrow(
"Invalid location reference 'http://blah', please prefix it with 'url:', e.g. 'url:http://blah'",
expect(() => parseLocationRef('http://blah')).toThrow(
"Invalid location ref 'http://blah', please prefix it with 'url:', e.g. 'url:http://blah'",
);
expect(() => parseLocationReference('https://bleh')).toThrow(
"Invalid location reference 'https://bleh', please prefix it with 'url:', e.g. 'url:https://bleh'",
expect(() => parseLocationRef('https://bleh')).toThrow(
"Invalid location ref 'https://bleh', please prefix it with 'url:', e.g. 'url:https://bleh'",
);
});
});
describe('stringifyLocationReference', () => {
describe('stringifyLocationRef', () => {
it('works for the simple case', () => {
expect(
stringifyLocationReference({
stringifyLocationRef({
type: 'url',
target: 'https://www.google.com',
}),
@@ -64,12 +64,12 @@ describe('stringifyLocationReference', () => {
});
it('rejects faulty inputs', () => {
expect(() =>
stringifyLocationReference({ type: '', target: 'hello' }),
).toThrow('Unable to stringify location reference, empty type');
expect(() =>
stringifyLocationReference({ type: 'hello', target: '' }),
).toThrow('Unable to stringify location reference, empty target');
expect(() => stringifyLocationRef({ type: '', target: 'hello' })).toThrow(
'Unable to stringify location ref, empty type',
);
expect(() => stringifyLocationRef({ type: 'hello', target: '' })).toThrow(
'Unable to stringify location ref, empty target',
);
});
});
+47 -10
View File
@@ -26,36 +26,53 @@ import { LOCATION_ANNOTATION, SOURCE_LOCATION_ANNOTATION } from './annotation';
* @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): {
export function parseLocationReference(ref: string) {
return parseLocationRef(ref);
}
/**
* Parses a string form location reference.
*
* @remarks
*
* Note that the return type is not `LocationSpec`, because we do not want to
* conflate the string form with the additional properties of that type.
*
* @public
* @param ref - A string-form location ref, e.g. `'url:https://host'`
* @returns A location ref, e.g. `{ type: 'url', target: 'https://host' }`
*/
export function parseLocationRef(ref: string): {
type: string;
target: string;
} {
if (typeof ref !== 'string') {
throw new TypeError(
`Unable to parse location reference '${ref}', unexpected argument ${typeof ref}`,
`Unable to parse location ref '${ref}', unexpected argument ${typeof ref}`,
);
}
const splitIndex = ref.indexOf(':');
if (splitIndex < 0) {
throw new TypeError(
`Unable to parse location reference '${ref}', expected '<type>:<target>', e.g. 'url:https://host/path'`,
`Unable to parse location ref '${ref}', expected '<type>:<target>', e.g. 'url:https://host/path'`,
);
}
const type = ref.substr(0, splitIndex).trim();
const target = ref.substr(splitIndex + 1).trim();
const type = ref.substring(0, splitIndex).trim();
const target = ref.substring(splitIndex + 1).trim();
if (!type || !target) {
throw new TypeError(
`Unable to parse location reference '${ref}', expected '<type>:<target>', e.g. 'url:https://host/path'`,
`Unable to parse location ref '${ref}', expected '<type>:<target>', e.g. 'url:https://host/path'`,
);
}
if (type === 'http' || type === 'https') {
throw new TypeError(
`Invalid location reference '${ref}', please prefix it with 'url:', e.g. 'url:${ref}'`,
`Invalid location ref '${ref}', please prefix it with 'url:', e.g. 'url:${ref}'`,
);
}
@@ -73,17 +90,37 @@ export function parseLocationReference(ref: string): {
* @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.
*
* @remarks
*
* Note that the input type is not `LocationSpec`, because we do not want to
* conflate the string form with the additional properties of that type.
*
* @public
* @param ref - A location ref, e.g. `{ type: 'url', target: 'https://host' }`
* @returns A string-form location ref, e.g. `'url:https://host'`
*/
export function stringifyLocationRef(ref: {
type: string;
target: string;
}): string {
const { type, target } = ref;
if (!type) {
throw new TypeError(`Unable to stringify location reference, empty type`);
throw new TypeError(`Unable to stringify location ref, empty type`);
} else if (!target) {
throw new TypeError(`Unable to stringify location reference, empty target`);
throw new TypeError(`Unable to stringify location ref, empty target`);
}
return `${type}:${target}`;
@@ -114,5 +151,5 @@ export function getEntitySourceLocation(entity: Entity): {
);
}
return parseLocationReference(locationRef);
return parseLocationRef(locationRef);
}
+4 -2
View File
@@ -20,8 +20,10 @@ export {
SOURCE_LOCATION_ANNOTATION,
} from './annotation';
export {
parseLocationReference,
stringifyLocationReference,
getEntitySourceLocation,
parseLocationRef,
parseLocationReference,
stringifyLocationRef,
stringifyLocationReference,
} from './helpers';
export type { Location, LocationSpec } from './types';
+2 -2
View File
@@ -18,7 +18,7 @@ import { resolveSafeChildPath, UrlReader } from '@backstage/backend-common';
import {
Entity,
getEntitySourceLocation,
parseLocationReference,
parseLocationRef,
} from '@backstage/catalog-model';
import { InputError } from '@backstage/errors';
import { ScmIntegrationRegistry } from '@backstage/integration';
@@ -42,7 +42,7 @@ export const parseReferenceAnnotation = (
);
}
const { type, target } = parseLocationReference(annotation);
const { type, target } = parseLocationRef(annotation);
return {
type: type as RemoteProtocol,
target,
@@ -21,7 +21,7 @@ import {
LOCATION_ANNOTATION,
ORIGIN_LOCATION_ANNOTATION,
SOURCE_LOCATION_ANNOTATION,
stringifyLocationReference,
stringifyLocationRef,
VIEW_URL_ANNOTATION,
} from '@backstage/catalog-model';
import { ScmIntegrationRegistry } from '@backstage/integration';
@@ -58,7 +58,7 @@ export class AnnotateLocationEntityProcessor implements CatalogProcessor {
});
if (sourceUrl) {
sourceLocation = stringifyLocationReference({
sourceLocation = stringifyLocationRef({
type: 'url',
target: sourceUrl,
});
@@ -70,9 +70,9 @@ export class AnnotateLocationEntityProcessor implements CatalogProcessor {
metadata: {
annotations: pickBy(
{
[LOCATION_ANNOTATION]: stringifyLocationReference(location),
[LOCATION_ANNOTATION]: stringifyLocationRef(location),
[ORIGIN_LOCATION_ANNOTATION]:
stringifyLocationReference(originLocation),
stringifyLocationRef(originLocation),
[VIEW_URL_ANNOTATION]: viewUrl,
[EDIT_URL_ANNOTATION]: editUrl,
[SOURCE_LOCATION_ANNOTATION]: sourceLocation,
@@ -17,7 +17,7 @@
import {
Entity,
LocationSpec,
stringifyLocationReference,
stringifyLocationRef,
} from '@backstage/catalog-model';
import lodash from 'lodash';
import yaml from 'yaml';
@@ -32,7 +32,7 @@ export function* parseEntityYaml(
try {
documents = yaml.parseAllDocuments(data.toString('utf8')).filter(d => d);
} catch (e) {
const loc = stringifyLocationReference(location);
const loc = stringifyLocationRef(location);
const message = `Failed to parse YAML at ${loc}, ${e}`;
yield result.generalError(location, message);
return;
@@ -40,7 +40,7 @@ export function* parseEntityYaml(
for (const document of documents) {
if (document.errors?.length) {
const loc = stringifyLocationReference(location);
const loc = stringifyLocationRef(location);
const message = `YAML error at ${loc}, ${document.errors[0]}`;
yield result.generalError(location, message);
} else {
@@ -19,9 +19,9 @@ import {
EntityPolicy,
LocationEntity,
LocationSpec,
parseLocationReference,
parseLocationRef,
stringifyEntityRef,
stringifyLocationReference,
stringifyLocationRef,
} from '@backstage/catalog-model';
import {
assertError,
@@ -119,10 +119,8 @@ export class DefaultCatalogProcessingOrchestrator
// source-location? - maybe probably doesn't exist yet?
const context: Context = {
entityRef: stringifyEntityRef(entity),
location: parseLocationReference(getEntityLocationRef(entity)),
originLocation: parseLocationReference(
getEntityOriginLocationRef(entity),
),
location: parseLocationRef(getEntityLocationRef(entity)),
originLocation: parseLocationRef(getEntityOriginLocationRef(entity)),
cache,
collector,
};
@@ -149,9 +147,9 @@ export class DefaultCatalogProcessingOrchestrator
throw new NotAllowedError(
`Entity ${stringifyEntityRef(
deferredEntity.entity,
)} at ${stringifyLocationReference(
)} at ${stringifyLocationRef(
context.location,
)}, originated at ${stringifyLocationReference(
)}, originated at ${stringifyLocationRef(
context.originLocation,
)}, is not of an allowed kind for that location`,
);
@@ -19,7 +19,7 @@ import {
EntityRelationSpec,
LOCATION_ANNOTATION,
ORIGIN_LOCATION_ANNOTATION,
stringifyLocationReference,
stringifyLocationRef,
} from '@backstage/catalog-model';
import { assertError } from '@backstage/errors';
import { Logger } from 'winston';
@@ -82,7 +82,7 @@ export class ProcessorOutputCollector {
return;
}
const location = stringifyLocationReference(i.location);
const location = stringifyLocationRef(i.location);
// Note that at this point, we have only validated the envelope part of
// the entity data. Annotations are not part of that, so we have to be
@@ -21,7 +21,7 @@ import {
LOCATION_ANNOTATION,
ORIGIN_LOCATION_ANNOTATION,
stringifyEntityRef,
stringifyLocationReference,
stringifyLocationRef,
} from '@backstage/catalog-model';
import { createHash } from 'crypto';
@@ -45,7 +45,7 @@ export function locationSpecToLocationEntity(
throw new Error(
`Parent entity '${stringifyEntityRef(
parentEntity,
)}' of location '${stringifyLocationReference(
)}' of location '${stringifyLocationRef(
location,
)}' does not have a location annotation`,
);
@@ -57,14 +57,14 @@ export function locationSpecToLocationEntity(
throw new Error(
`Parent entity '${stringifyEntityRef(
parentEntity,
)}' of location '${stringifyLocationReference(
)}' of location '${stringifyLocationRef(
location,
)}' does not have an origin location annotation`,
);
}
originLocation = maybeOriginLocation;
} else {
ownLocation = stringifyLocationReference(location);
ownLocation = stringifyLocationRef(location);
originLocation = ownLocation;
}
@@ -16,7 +16,7 @@
import {
Entity,
parseLocationReference,
parseLocationRef,
SOURCE_LOCATION_ANNOTATION,
} from '@backstage/catalog-model';
import { ScmIntegrationRegistry } from '@backstage/integration';
@@ -38,7 +38,7 @@ export function getEntitySourceLocation(
}
try {
const sourceLocationRef = parseLocationReference(sourceLocation);
const sourceLocationRef = parseLocationRef(sourceLocation);
const integration = scmIntegrationsApi.byUrl(sourceLocationRef.target);
return {
locationTargetUrl: sourceLocationRef.target,
+2 -2
View File
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { parseLocationReference } from '@backstage/catalog-model';
import { parseLocationRef } from '@backstage/catalog-model';
import { InputError } from '@backstage/errors';
import { ScmIntegrationRegistry } from '@backstage/integration';
import { graphql } from '@octokit/graphql';
@@ -27,7 +27,7 @@ const getBaseUrl = (
return 'https://api.github.com';
}
const location = parseLocationReference(host);
const location = parseLocationRef(host);
if (location.type !== 'github' && location.type !== 'url') {
return 'https://api.github.com';
}
@@ -17,7 +17,7 @@
import {
Entity,
LOCATION_ANNOTATION,
parseLocationReference,
parseLocationRef,
SOURCE_LOCATION_ANNOTATION,
} from '@backstage/catalog-model';
import { Config } from '@backstage/config';
@@ -67,7 +67,7 @@ export function getEntityBaseUrl(entity: Entity): string | undefined {
return undefined;
}
const { type, target } = parseLocationReference(location);
const { type, target } = parseLocationRef(location);
if (type === 'url') {
return target;
} else if (type === 'file') {
@@ -21,7 +21,7 @@ import {
SOURCE_LOCATION_ANNOTATION,
serializeEntityRef,
Entity,
parseLocationReference,
parseLocationRef,
} from '@backstage/catalog-model';
import { TodoReader } from '../lib';
import { ListTodosRequest, ListTodosResponse, TodoService } from './types';
@@ -130,7 +130,7 @@ export class TodoReaderService implements TodoService {
const sourceLocation =
entity.metadata.annotations?.[SOURCE_LOCATION_ANNOTATION];
if (sourceLocation) {
const parsed = parseLocationReference(sourceLocation);
const parsed = parseLocationRef(sourceLocation);
if (parsed.type !== 'url') {
throw new InputError(
`Invalid entity source location type for ${serializeEntityRef(
@@ -143,7 +143,7 @@ export class TodoReaderService implements TodoService {
const location = entity.metadata.annotations?.[LOCATION_ANNOTATION];
if (location) {
const parsed = parseLocationReference(location);
const parsed = parseLocationRef(location);
if (parsed.type !== 'url') {
throw new InputError(
`Invalid entity location type for ${serializeEntityRef(