diff --git a/.changeset/2803.md b/.changeset/2803.md new file mode 100644 index 0000000000000..3a4773757f738 --- /dev/null +++ b/.changeset/2803.md @@ -0,0 +1,26 @@ +--- +'@backstage/plugin-catalog-backend': minor +--- + +Remove the backstage.io/definition-at-location annotation. +The annotation was superseded by the placeholder processor. + +```yaml +apiVersion: backstage.io/v1alpha1 +kind: API +metadata: + name: spotify + description: The Spotify web API + tags: + - spotify + - rest + annotations: + # Don't use this annotation, but the placeholder $text instead (see below). + backstage.io/definition-at-location: 'url:https://raw.githubusercontent.com/APIs-guru/openapi-directory/master/APIs/spotify.com/v1/swagger.yaml' +spec: + type: openapi + lifecycle: production + owner: spotify@example.com + definition: + $text: https://raw.githubusercontent.com/APIs-guru/openapi-directory/master/APIs/spotify.com/v1/swagger.yaml +``` diff --git a/docs/features/software-catalog/well-known-annotations.md b/docs/features/software-catalog/well-known-annotations.md index 757e0461a9025..40a4ca3ea19a4 100644 --- a/docs/features/software-catalog/well-known-annotations.md +++ b/docs/features/software-catalog/well-known-annotations.md @@ -41,27 +41,6 @@ expecting a two-item array out of it. The format of the target part is type-dependent and could conceivably even be an empty string, but the separator colon is always present. -### backstage.io/definition-at-location - -```yaml -# Example -apiVersion: backstage.io/v1alpha1 -kind: API -metadata: - name: petstore - annotations: - backstage.io/definition-at-location: 'url:https://petstore.swagger.io/v2/swagger.json' -spec: - type: openapi -``` - -This annotation allows to fetch an API definition from another location, instead -of wrapping the API definition inside the definition field. This allows to -easily consume existing API definition. The definition is fetched during -ingestion by a processor and included in the entity. It is updated on every -refresh. The annotation contains a location reference string that contains the -location processor type and the target. - ### backstage.io/techdocs-ref ```yaml @@ -205,6 +184,25 @@ This annotation was used for a while to enable the GitHub Actions feature. This is now instead using the [github.com/project-slug](#github-com-project-slug) annotation, with the same value format. +### backstage.io/definition-at-location + +This annotation allowed to load the API definition from another location. Now +placeholders can be used instead: + +``` +apiVersion: backstage.io/v1alpha1 +kind: API +metadata: + name: petstore + description: The Petstore API +spec: + type: openapi + lifecycle: production + owner: petstore@example.com + definition: + $text: https://petstore.swagger.io/v2/swagger.json +``` + ## Links - [Descriptor Format: annotations](descriptor-format.md#annotations-optional) diff --git a/plugins/catalog-backend/src/ingestion/LocationReaders.ts b/plugins/catalog-backend/src/ingestion/LocationReaders.ts index fcc608eb51efa..c3f0989a68c7d 100644 --- a/plugins/catalog-backend/src/ingestion/LocationReaders.ts +++ b/plugins/catalog-backend/src/ingestion/LocationReaders.ts @@ -26,7 +26,6 @@ import { Config, ConfigReader } from '@backstage/config'; import { Logger } from 'winston'; import { CatalogRulesEnforcer } from './CatalogRules'; import { AnnotateLocationEntityProcessor } from './processors/AnnotateLocationEntityProcessor'; -import { ApiDefinitionAtLocationProcessor } from './processors/ApiDefinitionAtLocationProcessor'; import { AzureApiReaderProcessor } from './processors/AzureApiReaderProcessor'; import { BitbucketApiReaderProcessor } from './processors/BitbucketApiReaderProcessor'; import { CodeOwnersProcessor } from './processors/CodeOwnersProcessor'; @@ -127,7 +126,6 @@ export class LocationReaders implements LocationReader { new YamlProcessor(), PlaceholderProcessor.default(), new CodeOwnersProcessor(), - new ApiDefinitionAtLocationProcessor(), new EntityPolicyProcessor(entityPolicy), new LocationRefProcessor(), new AnnotateLocationEntityProcessor(), diff --git a/plugins/catalog-backend/src/ingestion/processors/ApiDefinitionAtLocationProcessor.test.ts b/plugins/catalog-backend/src/ingestion/processors/ApiDefinitionAtLocationProcessor.test.ts deleted file mode 100644 index 6ae656233957b..0000000000000 --- a/plugins/catalog-backend/src/ingestion/processors/ApiDefinitionAtLocationProcessor.test.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { ApiEntity, Entity, LocationSpec } from '@backstage/catalog-model'; -/* - * 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 { ApiDefinitionAtLocationProcessor } from './ApiDefinitionAtLocationProcessor'; - -describe('ApiDefinitionAtLocationProcessor', () => { - let processor: ApiDefinitionAtLocationProcessor; - let entity: Entity; - let location: LocationSpec; - - beforeEach(() => { - processor = new ApiDefinitionAtLocationProcessor(); - entity = { - apiVersion: 'backstage.io/v1alpha1', - kind: 'API', - metadata: { - name: 'test', - }, - spec: { - lifecycle: 'production', - owner: 'info@example.com', - type: 'openapi', - definition: 'Hello', - }, - }; - location = { - type: 'url', - target: `http://example.com/api.yaml`, - }; - }); - - it('should skip entities without annotation', async () => { - const read = jest.fn().mockRejectedValue(new Error('boo')); - - const generated = (await processor.processEntity( - entity, - location, - () => {}, - read, - )) as ApiEntity; - - expect(generated.spec.definition).toBe('Hello'); - }); - - it('should load from location', async () => { - entity.metadata.annotations = { - 'backstage.io/definition-at-location': - 'url:http://example.com/openapi.yaml', - }; - - const read = jest.fn().mockResolvedValue(Buffer.from('Hello')); - - const generated = (await processor.processEntity( - entity, - location, - () => {}, - read, - )) as ApiEntity; - - expect(generated.spec.definition).toBe('Hello'); - expect(read.mock.calls[0][0]).toStrictEqual({ - type: 'url', - target: 'http://example.com/openapi.yaml', - }); - }); - - it('should throw errors while loading', async () => { - entity.metadata.annotations = { - 'backstage.io/definition-at-location': 'missing', - }; - - const read = jest - .fn() - .mockRejectedValue(new Error('Failed to load location')); - - await expect( - processor.processEntity(entity, location, () => {}, read), - ).rejects.toThrow('Failed to load location'); - }); -}); diff --git a/plugins/catalog-backend/src/ingestion/processors/ApiDefinitionAtLocationProcessor.ts b/plugins/catalog-backend/src/ingestion/processors/ApiDefinitionAtLocationProcessor.ts deleted file mode 100644 index e64d112e9c8b1..0000000000000 --- a/plugins/catalog-backend/src/ingestion/processors/ApiDefinitionAtLocationProcessor.ts +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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 { ApiEntity, Entity, LocationSpec } from '@backstage/catalog-model'; -import { - LocationProcessor, - LocationProcessorEmit, - LocationProcessorRead, -} from './types'; - -const DEFINITION_AT_LOCATION_ANNOTATION = 'backstage.io/definition-at-location'; - -export class ApiDefinitionAtLocationProcessor implements LocationProcessor { - async processEntity( - entity: Entity, - _location: LocationSpec, - _emit: LocationProcessorEmit, - read: LocationProcessorRead, - ): Promise { - if ( - entity.kind !== 'API' || - !entity.metadata.annotations || - !entity.metadata.annotations[DEFINITION_AT_LOCATION_ANNOTATION] - ) { - return entity; - } - - const reference = - entity.metadata.annotations[DEFINITION_AT_LOCATION_ANNOTATION]; - const { type, target } = extractReference(reference); - const data = await read({ type, target }); - const definition = data.toString(); - const apiEntity = entity as ApiEntity; - apiEntity.spec.definition = definition; - - return entity; - } -} - -function extractReference(reference: string): { type: string; target: string } { - const delimiterIndex = reference.indexOf(':'); - const type = reference.slice(0, delimiterIndex); - const target = reference.slice(delimiterIndex + 1); - - return { type, target }; -} diff --git a/plugins/catalog-backend/src/ingestion/processors/index.ts b/plugins/catalog-backend/src/ingestion/processors/index.ts index 0ce7f11a5fcce..c9453d02470d3 100644 --- a/plugins/catalog-backend/src/ingestion/processors/index.ts +++ b/plugins/catalog-backend/src/ingestion/processors/index.ts @@ -20,7 +20,6 @@ export { results }; export * from './types'; export { AnnotateLocationEntityProcessor } from './AnnotateLocationEntityProcessor'; -export { ApiDefinitionAtLocationProcessor } from './ApiDefinitionAtLocationProcessor'; export { AzureApiReaderProcessor } from './AzureApiReaderProcessor'; export { BitbucketApiReaderProcessor } from './BitbucketApiReaderProcessor'; export { CodeOwnersProcessor } from './CodeOwnersProcessor';