diff --git a/.changeset/two-jars-melt.md b/.changeset/two-jars-melt.md new file mode 100644 index 0000000000..d6f0166885 --- /dev/null +++ b/.changeset/two-jars-melt.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-techdocs-backend': minor +'@backstage/plugin-techdocs-node': minor +--- + +Expose an extension point to set a custom build strategy and move `DocsBuildStrategy` and `ShouldBuildParameters` types to `@backstage/plugin-techdocs-node` diff --git a/plugins/techdocs-backend/api-report.md b/plugins/techdocs-backend/api-report.md index b8974e6d4f..6e2fbc4c53 100644 --- a/plugins/techdocs-backend/api-report.md +++ b/plugins/techdocs-backend/api-report.md @@ -7,7 +7,7 @@ import { CatalogApi } from '@backstage/catalog-client'; import { CatalogClient } from '@backstage/catalog-client'; import { Config } from '@backstage/config'; import { DefaultTechDocsCollatorFactory as DefaultTechDocsCollatorFactory_2 } from '@backstage/plugin-search-backend-module-techdocs'; -import { Entity } from '@backstage/catalog-model'; +import { DocsBuildStrategy } from '@backstage/plugin-techdocs-node'; import express from 'express'; import { GeneratorBuilder } from '@backstage/plugin-techdocs-node'; import { Knex } from 'knex'; @@ -17,6 +17,7 @@ import { PluginCacheManager } from '@backstage/backend-common'; import { PluginEndpointDiscovery } from '@backstage/backend-common'; import { PreparerBuilder } from '@backstage/plugin-techdocs-node'; import { PublisherBase } from '@backstage/plugin-techdocs-node'; +import { ShouldBuildParameters } from '@backstage/plugin-techdocs-node'; import type { TechDocsCollatorFactoryOptions as TechDocsCollatorFactoryOptions_2 } from '@backstage/plugin-search-backend-module-techdocs'; import { TechDocsDocument } from '@backstage/plugin-techdocs-node'; import { TokenManager } from '@backstage/backend-common'; @@ -48,11 +49,7 @@ export class DefaultTechDocsCollator { // @public @deprecated (undocumented) export const DefaultTechDocsCollatorFactory: typeof DefaultTechDocsCollatorFactory_2; -// @public -export interface DocsBuildStrategy { - // (undocumented) - shouldBuild(params: ShouldBuildParameters): Promise; -} +export { DocsBuildStrategy }; // @public export type OutOfTheBoxDeploymentOptions = { @@ -86,10 +83,7 @@ export type RouterOptions = | RecommendedDeploymentOptions | OutOfTheBoxDeploymentOptions; -// @public -export type ShouldBuildParameters = { - entity: Entity; -}; +export { ShouldBuildParameters }; // @public @deprecated (undocumented) export type TechDocsCollatorFactoryOptions = TechDocsCollatorFactoryOptions_2; diff --git a/plugins/techdocs-backend/src/index.ts b/plugins/techdocs-backend/src/index.ts index dc5d87d1b3..cf70db39e8 100644 --- a/plugins/techdocs-backend/src/index.ts +++ b/plugins/techdocs-backend/src/index.ts @@ -25,8 +25,6 @@ export type { RouterOptions, RecommendedDeploymentOptions, OutOfTheBoxDeploymentOptions, - DocsBuildStrategy, - ShouldBuildParameters, } from './service'; export { @@ -41,6 +39,10 @@ export type { /** * @deprecated Use directly from @backstage/plugin-techdocs-node */ -export type { TechDocsDocument } from '@backstage/plugin-techdocs-node'; +export type { + DocsBuildStrategy, + ShouldBuildParameters, + TechDocsDocument, +} from '@backstage/plugin-techdocs-node'; export * from '@backstage/plugin-techdocs-node'; diff --git a/plugins/techdocs-backend/src/plugin.ts b/plugins/techdocs-backend/src/plugin.ts index 745370b67a..2dcde1a975 100644 --- a/plugins/techdocs-backend/src/plugin.ts +++ b/plugins/techdocs-backend/src/plugin.ts @@ -25,9 +25,11 @@ import { } from '@backstage/backend-plugin-api'; import { + DocsBuildStrategy, Preparers, Generators, Publisher, + techdocsBuildStrategyExtensionPoint, } from '@backstage/plugin-techdocs-node'; import Docker from 'dockerode'; import { createRouter } from '@backstage/plugin-techdocs-backend'; @@ -39,6 +41,16 @@ import { createRouter } from '@backstage/plugin-techdocs-backend'; export const techdocsPlugin = createBackendPlugin({ pluginId: 'techdocs', register(env) { + let docsBuildStrategy: DocsBuildStrategy | undefined; + env.registerExtensionPoint(techdocsBuildStrategyExtensionPoint, { + setBuildStrategy(buildStrategy: DocsBuildStrategy) { + if (docsBuildStrategy) { + throw new Error('DocsBuildStrategy may only be set once'); + } + docsBuildStrategy = buildStrategy; + }, + }); + env.registerInit({ deps: { config: coreServices.rootConfig, @@ -82,6 +94,7 @@ export const techdocsPlugin = createBackendPlugin({ await createRouter({ logger: winstonLogger, cache: cacheManager, + docsBuildStrategy, preparers, generators, publisher, diff --git a/plugins/techdocs-backend/src/service/DocsBuildStrategy.test.ts b/plugins/techdocs-backend/src/service/DefaultDocsBuildStrategy.test.ts similarity index 96% rename from plugins/techdocs-backend/src/service/DocsBuildStrategy.test.ts rename to plugins/techdocs-backend/src/service/DefaultDocsBuildStrategy.test.ts index 84bd960f8f..7868135b08 100644 --- a/plugins/techdocs-backend/src/service/DocsBuildStrategy.test.ts +++ b/plugins/techdocs-backend/src/service/DefaultDocsBuildStrategy.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { DefaultDocsBuildStrategy } from './DocsBuildStrategy'; +import { DefaultDocsBuildStrategy } from './DefaultDocsBuildStrategy'; import { ConfigReader } from '@backstage/config'; const MockedConfigReader = ConfigReader as jest.MockedClass< diff --git a/plugins/techdocs-backend/src/service/DocsBuildStrategy.ts b/plugins/techdocs-backend/src/service/DefaultDocsBuildStrategy.ts similarity index 66% rename from plugins/techdocs-backend/src/service/DocsBuildStrategy.ts rename to plugins/techdocs-backend/src/service/DefaultDocsBuildStrategy.ts index 42a16234f9..fe0f5206ba 100644 --- a/plugins/techdocs-backend/src/service/DocsBuildStrategy.ts +++ b/plugins/techdocs-backend/src/service/DefaultDocsBuildStrategy.ts @@ -13,28 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { Entity } from '@backstage/catalog-model'; import { Config } from '@backstage/config'; +import { + DocsBuildStrategy, + ShouldBuildParameters, +} from '@backstage/plugin-techdocs-node'; -/** - * Parameters passed to the shouldBuild method on the DocsBuildStrategy interface - * - * @public - */ -export type ShouldBuildParameters = { - entity: Entity; -}; - -/** - * A strategy for when to build TechDocs locally, and when to skip building TechDocs (allowing for an external build) - * - * @public - */ -export interface DocsBuildStrategy { - shouldBuild(params: ShouldBuildParameters): Promise; -} - -export class DefaultDocsBuildStrategy { +export class DefaultDocsBuildStrategy implements DocsBuildStrategy { private readonly config: Config; private constructor(config: Config) { diff --git a/plugins/techdocs-backend/src/service/index.ts b/plugins/techdocs-backend/src/service/index.ts index 7355a34e32..0065e33a2a 100644 --- a/plugins/techdocs-backend/src/service/index.ts +++ b/plugins/techdocs-backend/src/service/index.ts @@ -20,7 +20,3 @@ export type { RecommendedDeploymentOptions, OutOfTheBoxDeploymentOptions, } from './router'; -export type { - DocsBuildStrategy, - ShouldBuildParameters, -} from './DocsBuildStrategy'; diff --git a/plugins/techdocs-backend/src/service/router.test.ts b/plugins/techdocs-backend/src/service/router.test.ts index 0c049c00f2..224a87cb43 100644 --- a/plugins/techdocs-backend/src/service/router.test.ts +++ b/plugins/techdocs-backend/src/service/router.test.ts @@ -22,6 +22,7 @@ import { } from '@backstage/backend-common'; import { ConfigReader } from '@backstage/config'; import { + DocsBuildStrategy, GeneratorBuilder, PreparerBuilder, PublisherBase, @@ -32,7 +33,6 @@ import { DocsSynchronizer, DocsSynchronizerSyncOpts } from './DocsSynchronizer'; import { CachedEntityLoader } from './CachedEntityLoader'; import { createEventStream, createRouter, RouterOptions } from './router'; import { TechDocsCache } from '../cache'; -import { DocsBuildStrategy } from './DocsBuildStrategy'; jest.mock('@backstage/catalog-client'); jest.mock('@backstage/config'); diff --git a/plugins/techdocs-backend/src/service/router.ts b/plugins/techdocs-backend/src/service/router.ts index 855d8b02f4..734c1f40de 100644 --- a/plugins/techdocs-backend/src/service/router.ts +++ b/plugins/techdocs-backend/src/service/router.ts @@ -22,6 +22,7 @@ import { stringifyEntityRef } from '@backstage/catalog-model'; import { Config } from '@backstage/config'; import { NotFoundError } from '@backstage/errors'; import { + DocsBuildStrategy, GeneratorBuilder, getLocationForEntity, PreparerBuilder, @@ -34,10 +35,7 @@ import { ScmIntegrations } from '@backstage/integration'; import { DocsSynchronizer, DocsSynchronizerSyncOpts } from './DocsSynchronizer'; import { createCacheMiddleware, TechDocsCache } from '../cache'; import { CachedEntityLoader } from './CachedEntityLoader'; -import { - DefaultDocsBuildStrategy, - DocsBuildStrategy, -} from './DocsBuildStrategy'; +import { DefaultDocsBuildStrategy } from './DefaultDocsBuildStrategy'; import * as winston from 'winston'; import { PassThrough } from 'stream'; diff --git a/plugins/techdocs-node/api-report.md b/plugins/techdocs-node/api-report.md index 656db6ae36..843190ceb8 100644 --- a/plugins/techdocs-node/api-report.md +++ b/plugins/techdocs-node/api-report.md @@ -10,6 +10,7 @@ import { Config } from '@backstage/config'; import { ContainerRunner } from '@backstage/backend-common'; import { Entity } from '@backstage/catalog-model'; import express from 'express'; +import { ExtensionPoint } from '@backstage/backend-plugin-api'; import { IndexableDocument } from '@backstage/plugin-search-common'; import { Logger } from 'winston'; import { PluginEndpointDiscovery } from '@backstage/backend-common'; @@ -24,6 +25,12 @@ export class DirectoryPreparer implements PreparerBase { shouldCleanPreparedDirectory(): boolean; } +// @public +export interface DocsBuildStrategy { + // (undocumented) + shouldBuild(params: ShouldBuildParameters): Promise; +} + // @public export type ETag = string; @@ -226,9 +233,23 @@ export type ReadinessResponse = { // @public export type RemoteProtocol = 'url' | 'dir'; +// @public +export type ShouldBuildParameters = { + entity: Entity; +}; + // @public export type SupportedGeneratorKey = 'techdocs' | string; +// @public +export interface TechdocsBuildStrategyExtensionPoint { + // (undocumented) + setBuildStrategy(buildStrategy: DocsBuildStrategy): void; +} + +// @public +export const techdocsBuildStrategyExtensionPoint: ExtensionPoint; + // @public export interface TechDocsDocument extends IndexableDocument { kind: string; diff --git a/plugins/techdocs-node/package.json b/plugins/techdocs-node/package.json index 4ec11fde71..6258e7b9a3 100644 --- a/plugins/techdocs-node/package.json +++ b/plugins/techdocs-node/package.json @@ -47,6 +47,7 @@ "@azure/identity": "^3.2.1", "@azure/storage-blob": "^12.5.0", "@backstage/backend-common": "workspace:^", + "@backstage/backend-plugin-api": "workspace:^", "@backstage/catalog-model": "workspace:^", "@backstage/config": "workspace:^", "@backstage/errors": "workspace:^", diff --git a/plugins/techdocs-node/src/extensions.ts b/plugins/techdocs-node/src/extensions.ts new file mode 100644 index 0000000000..0de6fa1e27 --- /dev/null +++ b/plugins/techdocs-node/src/extensions.ts @@ -0,0 +1,36 @@ +/* + * Copyright 2023 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 { createExtensionPoint } from '@backstage/backend-plugin-api'; +import { DocsBuildStrategy } from './techdocsTypes'; + +/** + * Extension point type for setting a custom build strategy. + * + * @public + */ +export interface TechdocsBuildStrategyExtensionPoint { + setBuildStrategy(buildStrategy: DocsBuildStrategy): void; +} + +/** + * Extension point for setting a custom build strategy. + * + * @public + */ +export const techdocsBuildStrategyExtensionPoint = + createExtensionPoint({ + id: 'techdocs.buildStrategy', + }); diff --git a/plugins/techdocs-node/src/index.ts b/plugins/techdocs-node/src/index.ts index a2acf84611..0c4b5bb67f 100644 --- a/plugins/techdocs-node/src/index.ts +++ b/plugins/techdocs-node/src/index.ts @@ -23,3 +23,7 @@ export * from './stages'; export * from './helpers'; export * from './techdocsTypes'; +export { + techdocsBuildStrategyExtensionPoint, + type TechdocsBuildStrategyExtensionPoint, +} from './extensions'; diff --git a/plugins/techdocs-node/src/techdocsTypes.ts b/plugins/techdocs-node/src/techdocsTypes.ts index 77436b35d5..6fc3ffc65f 100644 --- a/plugins/techdocs-node/src/techdocsTypes.ts +++ b/plugins/techdocs-node/src/techdocsTypes.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import { Entity } from '@backstage/catalog-model'; import { IndexableDocument } from '@backstage/plugin-search-common'; /** @@ -46,3 +47,21 @@ export interface TechDocsDocument extends IndexableDocument { */ path: string; } + +/** + * Parameters passed to the shouldBuild method on the DocsBuildStrategy interface + * + * @public + */ +export type ShouldBuildParameters = { + entity: Entity; +}; + +/** + * A strategy for when to build TechDocs locally, and when to skip building TechDocs (allowing for an external build) + * + * @public + */ +export interface DocsBuildStrategy { + shouldBuild(params: ShouldBuildParameters): Promise; +} diff --git a/yarn.lock b/yarn.lock index fd3b9da734..68ae329efc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9770,6 +9770,7 @@ __metadata: "@azure/identity": ^3.2.1 "@azure/storage-blob": ^12.5.0 "@backstage/backend-common": "workspace:^" + "@backstage/backend-plugin-api": "workspace:^" "@backstage/backend-test-utils": "workspace:^" "@backstage/catalog-model": "workspace:^" "@backstage/cli": "workspace:^"