diff --git a/docs/features/software-catalog/well-known-annotations.md b/docs/features/software-catalog/well-known-annotations.md index 795bf15621..3c8f836aed 100644 --- a/docs/features/software-catalog/well-known-annotations.md +++ b/docs/features/software-catalog/well-known-annotations.md @@ -70,7 +70,7 @@ The value of this annotation is a location reference string (see above). If this annotation is specified, it is expected to point to a repository that the TechDocs system can read and generate docs from. -### backstage.io/browser-view-url, backstage.io/browser-edit-url, backstage.io/browser-source-url +### backstage.io/browser-view-url, backstage.io/browser-edit-url ```yaml # Example: @@ -78,16 +78,26 @@ metadata: annotations: backstage.io/browser-view-url: https://some.website/catalog-info.yaml backstage.io/browser-edit-url: https://github.com/my-org/catalog/edit/master/my-service.jsonnet - backstage.io/browser-source-url: https://github.com/my-org/my-service ``` These annotations allow customising links from the catalog pages. The view URL should point to the canonical metadata YAML that governs this entity. The edit -URL should point to the source file for the metadata. The source URL should -point to the source code of the entity itself (where relevant, i.e. when the -entity is a `Component`). In the example above, `my-org` generates its catalog -data from Jsonnet files in a monorepo, and so for the `my-service` component, we -need three custom links. +URL should point to the source file for the metadata. In the example above, +`my-org` generates its catalog data from Jsonnet files in a monorepo, so the +view and edit links need changing. + +### backstage.io/source-location + +```yaml +# Example: +metadata: + annotations: + backstage.io/source-location: github:https://github.com/my-org/my-service +``` + +A `Location` reference that points to the source code of the entity (typically a +`Component`). Useful when catalog files do not get ingested from the source code +repository itself. ### jenkins.io/github-folder diff --git a/packages/catalog-model/src/location/annotation.ts b/packages/catalog-model/src/location/annotation.ts index 93f2fabea4..ba875c3edf 100644 --- a/packages/catalog-model/src/location/annotation.ts +++ b/packages/catalog-model/src/location/annotation.ts @@ -17,3 +17,5 @@ export const LOCATION_ANNOTATION = 'backstage.io/managed-by-location'; export const ORIGIN_LOCATION_ANNOTATION = 'backstage.io/managed-by-origin-location'; + +export const SOURCE_LOCATION_ANNOTATION = 'backstage.io/source-location'; diff --git a/packages/catalog-model/src/location/index.ts b/packages/catalog-model/src/location/index.ts index 8fd516120a..6cfb074613 100644 --- a/packages/catalog-model/src/location/index.ts +++ b/packages/catalog-model/src/location/index.ts @@ -20,4 +20,8 @@ export { locationSpecSchema, analyzeLocationSchema, } from './validation'; -export { LOCATION_ANNOTATION, ORIGIN_LOCATION_ANNOTATION } from './annotation'; +export { + LOCATION_ANNOTATION, + ORIGIN_LOCATION_ANNOTATION, + SOURCE_LOCATION_ANNOTATION, +} from './annotation'; diff --git a/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx b/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx index dfca528716..e99ec056d2 100644 --- a/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx +++ b/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx @@ -15,6 +15,7 @@ */ import { EntityProvider } from '@backstage/plugin-catalog-react'; +import { SOURCE_LOCATION_ANNOTATION } from '@backstage/catalog-model'; import { render } from '@testing-library/react'; import React from 'react'; import { AboutCard } from './AboutCard'; @@ -135,8 +136,8 @@ describe(' custom links', () => { 'backstage.io/managed-by-location': 'bitbucket:https://bitbucket.org/backstage/backstage/src/master/software.yaml', 'backstage.io/browser-edit-url': 'https://another.place', - 'backstage.io/browser-source-url': - 'https://another.place/backstage.git', + [SOURCE_LOCATION_ANNOTATION]: + 'url:https://another.place/backstage.git', }, }, spec: { diff --git a/plugins/catalog/src/components/AboutCard/AboutCard.tsx b/plugins/catalog/src/components/AboutCard/AboutCard.tsx index ee42281d31..6a13d78d14 100644 --- a/plugins/catalog/src/components/AboutCard/AboutCard.tsx +++ b/plugins/catalog/src/components/AboutCard/AboutCard.tsx @@ -16,7 +16,9 @@ import { Entity, + LocationSpec, ENTITY_DEFAULT_NAMESPACE, + SOURCE_LOCATION_ANNOTATION, RELATION_PROVIDES_API, } from '@backstage/catalog-model'; import { HeaderIconLinkRow } from '@backstage/core'; @@ -34,7 +36,7 @@ import EditIcon from '@material-ui/icons/Edit'; import ExtensionIcon from '@material-ui/icons/Extension'; import GitHubIcon from '@material-ui/icons/GitHub'; import React from 'react'; -import { findLocationForEntityMeta } from '../../data/utils'; +import { findLocationForEntityMeta, parseLocation } from '../../data/utils'; import { findEditUrl, determineUrlType } from '../actions'; import { AboutContent } from './AboutContent'; @@ -60,23 +62,35 @@ type CodeLinkInfo = { href?: string; }; +function getSourceLocationForEntity( + entity: Entity, + location?: LocationSpec, +): LocationSpec | undefined { + const annotation = entity.metadata?.annotations?.[SOURCE_LOCATION_ANNOTATION]; + const parsed = annotation && parseLocation(annotation); + + return parsed || location; +} + function getCodeLinkInfo(entity: Entity): CodeLinkInfo { - let sourceUrl = - entity.metadata?.annotations?.['backstage.io/browser-source-url']; const location = findLocationForEntityMeta(entity?.metadata); const editUrl = findEditUrl(entity, location); + let sourceLocation = getSourceLocationForEntity(entity, location); if (location) { - sourceUrl = sourceUrl || location.target; + sourceLocation = sourceLocation || location; const type = - location.type === 'url' ? determineUrlType(sourceUrl) : location.type; + sourceLocation.type === 'url' + ? determineUrlType(sourceLocation.target) + : sourceLocation.type; return { edithref: editUrl, icon: iconMap[type], - href: sourceUrl, + href: sourceLocation.target, }; } - return { edithref: editUrl, href: sourceUrl }; + + return { edithref: editUrl, href: sourceLocation?.target }; } type AboutCardProps = { diff --git a/plugins/catalog/src/data/utils.ts b/plugins/catalog/src/data/utils.ts index df14875092..ec63d94754 100644 --- a/plugins/catalog/src/data/utils.ts +++ b/plugins/catalog/src/data/utils.ts @@ -32,13 +32,17 @@ export function findLocationForEntityMeta( return undefined; } - const separatorIndex = annotation.indexOf(':'); + return parseLocation(annotation); +} + +export function parseLocation(reference: string): LocationSpec | undefined { + const separatorIndex = reference.indexOf(':'); if (separatorIndex === -1) { return undefined; } return { - type: annotation.substring(0, separatorIndex), - target: annotation.substring(separatorIndex + 1), + type: reference.substring(0, separatorIndex), + target: reference.substring(separatorIndex + 1), }; }