Merge pull request #3449 from SDA-SE/feat/provides-consumse-api

Replace implementsApis with providesApis and add consumesApis
This commit is contained in:
Oliver Sand
2020-11-26 17:27:30 +01:00
committed by GitHub
14 changed files with 175 additions and 15 deletions
+1 -1
View File
@@ -21,7 +21,7 @@ Right now, the following API formats are supported:
Other formats are displayed as plain text, but this can easily be extended.
To fill the catalog with APIs, [provide entities of kind API](https://backstage.io/docs/features/software-catalog/descriptor-format#kind-api).
To link that an component implements an API, see [`implementsApis` property on components](https://backstage.io/docs/features/software-catalog/descriptor-format#specimplementsapis-optional).
To link that a component provides or consumes an API, see the [`providesApis`](https://backstage.io/docs/features/software-catalog/descriptor-format#specprovidesapis-optional) and [`consumesApis`](https://backstage.io/docs/features/software-catalog/descriptor-format#specconsumesapis-optional) properties on the Component kind.
## Links
@@ -28,7 +28,7 @@ spec:
type: service
lifecycle: production
owner: guest
implementsApis:
providesApis:
- example-api
`;
@@ -49,8 +49,7 @@ export const MissingImplementsApisEmptyState = () => {
description={
<Typography>
Components can implement APIs that are displayed on this page. You
need to fill the <code>implementsApis</code> field to enable this
tool.
need to fill the <code>providesApis</code> field to enable this tool.
</Typography>
}
action={
@@ -71,7 +70,7 @@ export const MissingImplementsApisEmptyState = () => {
<Button
variant="contained"
color="primary"
href="https://backstage.io/docs/features/software-catalog/descriptor-format#specimplementsapis-optional"
href="https://backstage.io/docs/features/software-catalog/descriptor-format#specprovidesapis-optional"
>
Read more
</Button>
+3 -2
View File
@@ -15,14 +15,15 @@
*/
import React from 'react';
import { Entity } from '@backstage/catalog-model';
import { Entity, RELATION_PROVIDES_API } from '@backstage/catalog-model';
import { Route, Routes } from 'react-router';
import { catalogRoute } from '../routes';
import { EntityPageApi } from './EntityPageApi';
import { MissingImplementsApisEmptyState } from './MissingImplementsApisEmptyState';
const isPluginApplicableToEntity = (entity: Entity) => {
return ((entity.spec?.implementsApis as string[]) || []).length > 0;
// TODO: Also support RELATION_CONSUMES_API
return entity.relations?.some(r => r.type === RELATION_PROVIDES_API);
};
export const Router = ({ entity }: { entity: Entity }) =>
@@ -14,8 +14,16 @@
* limitations under the License.
*/
import { ComponentEntity } from '@backstage/catalog-model';
import {
ComponentEntity,
RELATION_PROVIDES_API,
} from '@backstage/catalog-model';
export const useComponentApiNames = (entity: ComponentEntity) => {
return (entity.spec?.implementsApis as string[]) || [];
// TODO: This code doesn't handle namespaces and kinds correctly, but will be removed soon
return (
entity.relations
?.filter(r => r.type === RELATION_PROVIDES_API)
?.map(r => r.target.name) || []
);
};
@@ -68,12 +68,14 @@ describe('BuiltinKindsEntityProcessor', () => {
owner: 'o',
lifecycle: 'l',
implementsApis: ['a'],
providesApis: ['b'],
consumesApis: ['c'],
},
};
await processor.postProcessEntity(entity, location, emit);
expect(emit).toBeCalledTimes(4);
expect(emit).toBeCalledTimes(8);
expect(emit).toBeCalledWith({
type: 'relation',
relation: {
@@ -106,6 +108,38 @@ describe('BuiltinKindsEntityProcessor', () => {
target: { kind: 'API', namespace: 'default', name: 'a' },
},
});
expect(emit).toBeCalledWith({
type: 'relation',
relation: {
source: { kind: 'API', namespace: 'default', name: 'b' },
type: 'apiProvidedBy',
target: { kind: 'Component', namespace: 'default', name: 'n' },
},
});
expect(emit).toBeCalledWith({
type: 'relation',
relation: {
source: { kind: 'Component', namespace: 'default', name: 'n' },
type: 'providesApi',
target: { kind: 'API', namespace: 'default', name: 'b' },
},
});
expect(emit).toBeCalledWith({
type: 'relation',
relation: {
source: { kind: 'API', namespace: 'default', name: 'c' },
type: 'apiConsumedBy',
target: { kind: 'Component', namespace: 'default', name: 'n' },
},
});
expect(emit).toBeCalledWith({
type: 'relation',
relation: {
source: { kind: 'Component', namespace: 'default', name: 'n' },
type: 'consumesApi',
target: { kind: 'API', namespace: 'default', name: 'c' },
},
});
});
it('generates relations for api entities', async () => {
@@ -26,8 +26,10 @@ import {
locationEntityV1alpha1Validator,
LocationSpec,
parseEntityRef,
RELATION_API_CONSUMED_BY,
RELATION_API_PROVIDED_BY,
RELATION_CHILD_OF,
RELATION_CONSUMES_API,
RELATION_HAS_MEMBER,
RELATION_MEMBER_OF,
RELATION_OWNED_BY,
@@ -138,6 +140,18 @@ export class BuiltinKindsEntityProcessor implements CatalogProcessor {
RELATION_PROVIDES_API,
RELATION_API_PROVIDED_BY,
);
doEmit(
component.spec.providesApis,
{ defaultKind: 'API', defaultNamespace: selfRef.namespace },
RELATION_PROVIDES_API,
RELATION_API_PROVIDED_BY,
);
doEmit(
component.spec.consumesApis,
{ defaultKind: 'API', defaultNamespace: selfRef.namespace },
RELATION_CONSUMES_API,
RELATION_API_CONSUMED_BY,
);
}
/*
@@ -18,6 +18,7 @@ import {
Entity,
ENTITY_DEFAULT_NAMESPACE,
RELATION_OWNED_BY,
RELATION_PROVIDES_API,
serializeEntityRef,
} from '@backstage/catalog-model';
import {
@@ -111,6 +112,8 @@ type AboutCardProps = {
export function AboutCard({ entity, variant }: AboutCardProps) {
const classes = useStyles();
const codeLink = getCodeLinkInfo(entity);
// TODO: Also support RELATION_CONSUMES_API here
const hasApis = entity.relations?.some(r => r.type === RELATION_PROVIDES_API);
return (
<Card className={variant === 'gridItem' ? classes.gridItemCard : ''}>
@@ -146,9 +149,9 @@ export function AboutCard({ entity, variant }: AboutCardProps) {
}/${entity.kind}/${entity.metadata.name}`}
/>
<IconLinkVertical
disabled={!entity.spec?.implementsApis}
disabled={!hasApis}
label="View API"
title={!entity.spec?.implementsApis ? 'No APIs available' : ''}
title={hasApis ? '' : 'No APIs available'}
icon={<ExtensionIcon />}
href="api"
/>