Merge pull request #25361 from johnphilip283/add-publisher-extension-point
TechDocs: Add publisher extension point
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-techdocs-backend': patch
|
||||
'@backstage/plugin-techdocs-node': patch
|
||||
---
|
||||
|
||||
Adds extension point for publishers to the techdocs backend
|
||||
@@ -29,11 +29,14 @@ import {
|
||||
PreparerBase,
|
||||
Preparers,
|
||||
Publisher,
|
||||
PublisherBase,
|
||||
PublisherType,
|
||||
RemoteProtocol,
|
||||
techdocsBuildsExtensionPoint,
|
||||
TechdocsGenerator,
|
||||
techdocsGeneratorExtensionPoint,
|
||||
techdocsPreparerExtensionPoint,
|
||||
techdocsPublisherExtensionPoint,
|
||||
} from '@backstage/plugin-techdocs-node';
|
||||
import { createRouter } from '@backstage/plugin-techdocs-backend';
|
||||
import * as winston from 'winston';
|
||||
@@ -85,6 +88,16 @@ export const techdocsPlugin = createBackendPlugin({
|
||||
},
|
||||
});
|
||||
|
||||
let customTechdocsPublisher: PublisherBase | undefined;
|
||||
env.registerExtensionPoint(techdocsPublisherExtensionPoint, {
|
||||
registerPublisher(type: PublisherType, publisher: PublisherBase) {
|
||||
if (customTechdocsPublisher) {
|
||||
throw new Error(`Publisher for type ${type} is already registered`);
|
||||
}
|
||||
customTechdocsPublisher = publisher;
|
||||
},
|
||||
});
|
||||
|
||||
env.registerInit({
|
||||
deps: {
|
||||
config: coreServices.rootConfig,
|
||||
@@ -128,6 +141,7 @@ export const techdocsPlugin = createBackendPlugin({
|
||||
const publisher = await Publisher.fromConfig(config, {
|
||||
logger: winstonLogger,
|
||||
discovery: discovery,
|
||||
customPublisher: customTechdocsPublisher,
|
||||
});
|
||||
|
||||
// checks if the publisher is working and logs the result
|
||||
|
||||
@@ -183,11 +183,15 @@ export class Preparers implements PreparerBuilder {
|
||||
}
|
||||
|
||||
// @public
|
||||
export class Publisher {
|
||||
export class Publisher implements PublisherBuilder {
|
||||
static fromConfig(
|
||||
config: Config,
|
||||
options: PublisherFactory,
|
||||
): Promise<PublisherBase>;
|
||||
// (undocumented)
|
||||
get(config: Config): PublisherBase;
|
||||
// (undocumented)
|
||||
register(type: PublisherType | 'techdocs', publisher: PublisherBase): void;
|
||||
}
|
||||
|
||||
// @public
|
||||
@@ -202,10 +206,17 @@ export interface PublisherBase {
|
||||
publish(request: PublishRequest): Promise<PublishResponse>;
|
||||
}
|
||||
|
||||
// @public
|
||||
export type PublisherBuilder = {
|
||||
register(type: PublisherType, publisher: PublisherBase): void;
|
||||
get(config: Config): PublisherBase;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type PublisherFactory = {
|
||||
logger: Logger;
|
||||
discovery: PluginEndpointDiscovery;
|
||||
customPublisher?: PublisherBase | undefined;
|
||||
};
|
||||
|
||||
// @public
|
||||
@@ -303,6 +314,15 @@ export interface TechdocsPreparerExtensionPoint {
|
||||
// @public
|
||||
export const techdocsPreparerExtensionPoint: ExtensionPoint<TechdocsPreparerExtensionPoint>;
|
||||
|
||||
// @public
|
||||
export interface TechdocsPublisherExtensionPoint {
|
||||
// (undocumented)
|
||||
registerPublisher(type: PublisherType, publisher: PublisherBase): void;
|
||||
}
|
||||
|
||||
// @public
|
||||
export const techdocsPublisherExtensionPoint: ExtensionPoint<TechdocsPublisherExtensionPoint>;
|
||||
|
||||
// @public
|
||||
export const transformDirLocation: (
|
||||
entity: Entity,
|
||||
|
||||
@@ -15,7 +15,13 @@
|
||||
*/
|
||||
import { createExtensionPoint } from '@backstage/backend-plugin-api';
|
||||
import { DocsBuildStrategy } from './techdocsTypes';
|
||||
import { PreparerBase, RemoteProtocol, TechdocsGenerator } from './stages';
|
||||
import {
|
||||
PreparerBase,
|
||||
PublisherBase,
|
||||
PublisherType,
|
||||
RemoteProtocol,
|
||||
TechdocsGenerator,
|
||||
} from './stages';
|
||||
import * as winston from 'winston';
|
||||
|
||||
/**
|
||||
@@ -75,3 +81,22 @@ export const techdocsPreparerExtensionPoint =
|
||||
createExtensionPoint<TechdocsPreparerExtensionPoint>({
|
||||
id: 'techdocs.preparer',
|
||||
});
|
||||
|
||||
/**
|
||||
* Extension point type for configuring a custom Techdocs publisher
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface TechdocsPublisherExtensionPoint {
|
||||
registerPublisher(type: PublisherType, publisher: PublisherBase): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension point for configuring a custom Techdocs publisher
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const techdocsPublisherExtensionPoint =
|
||||
createExtensionPoint<TechdocsPublisherExtensionPoint>({
|
||||
id: 'techdocs.publisher',
|
||||
});
|
||||
|
||||
@@ -27,7 +27,9 @@ export {
|
||||
techdocsBuildsExtensionPoint,
|
||||
techdocsGeneratorExtensionPoint,
|
||||
techdocsPreparerExtensionPoint,
|
||||
techdocsPublisherExtensionPoint,
|
||||
type TechdocsBuildsExtensionPoint,
|
||||
type TechdocsGeneratorExtensionPoint,
|
||||
type TechdocsPreparerExtensionPoint,
|
||||
type TechdocsPublisherExtensionPoint,
|
||||
} from './extensions';
|
||||
|
||||
@@ -23,4 +23,5 @@ export type {
|
||||
MigrateRequest,
|
||||
ReadinessResponse,
|
||||
TechDocsMetadata,
|
||||
PublisherBuilder,
|
||||
} from './types';
|
||||
|
||||
@@ -25,6 +25,7 @@ import { AwsS3Publish } from './awsS3';
|
||||
import { AzureBlobStoragePublish } from './azureBlobStorage';
|
||||
import { OpenStackSwiftPublish } from './openStackSwift';
|
||||
import { mockServices } from '@backstage/backend-test-utils';
|
||||
import { PublisherBase } from './types';
|
||||
|
||||
const logger = loggerToWinstonLogger(mockServices.logger.mock());
|
||||
const discovery: jest.Mocked<PluginEndpointDiscovery> = {
|
||||
@@ -184,4 +185,20 @@ describe('Publisher', () => {
|
||||
});
|
||||
expect(publisher).toBeInstanceOf(OpenStackSwiftPublish);
|
||||
});
|
||||
|
||||
it('registers a custom publisher if provided', async () => {
|
||||
const mockConfig = new ConfigReader({});
|
||||
|
||||
const customPublisher = {
|
||||
publish: jest.fn(),
|
||||
} as unknown as PublisherBase;
|
||||
|
||||
const publisher = await Publisher.fromConfig(mockConfig, {
|
||||
logger,
|
||||
discovery,
|
||||
customPublisher,
|
||||
});
|
||||
|
||||
expect(publisher).toBe(customPublisher);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -20,14 +20,45 @@ import { AzureBlobStoragePublish } from './azureBlobStorage';
|
||||
import { GoogleGCSPublish } from './googleStorage';
|
||||
import { LocalPublish } from './local';
|
||||
import { OpenStackSwiftPublish } from './openStackSwift';
|
||||
import { PublisherFactory, PublisherBase, PublisherType } from './types';
|
||||
import {
|
||||
PublisherFactory,
|
||||
PublisherBase,
|
||||
PublisherType,
|
||||
PublisherBuilder,
|
||||
} from './types';
|
||||
|
||||
/**
|
||||
* Factory class to create a TechDocs publisher based on defined publisher type in app config.
|
||||
* Uses `techdocs.publisher.type`.
|
||||
* @public
|
||||
*/
|
||||
export class Publisher {
|
||||
export class Publisher implements PublisherBuilder {
|
||||
private publishers: Map<PublisherType | 'techdocs', PublisherBase> =
|
||||
new Map();
|
||||
|
||||
register(type: PublisherType | 'techdocs', publisher: PublisherBase): void {
|
||||
this.publishers.set(type, publisher);
|
||||
}
|
||||
|
||||
get(config: Config): PublisherBase {
|
||||
const publisherType = (config.getOptionalString(
|
||||
'techdocs.publisher.type',
|
||||
) ?? 'local') as PublisherType;
|
||||
|
||||
if (!publisherType) {
|
||||
throw new Error('TechDocs publisher type not specified for the entity');
|
||||
}
|
||||
|
||||
const publisher = this.publishers.get(publisherType);
|
||||
if (!publisher) {
|
||||
throw new Error(
|
||||
`TechDocs publisher '${publisherType}' is not registered`,
|
||||
);
|
||||
}
|
||||
|
||||
return publisher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a instance of TechDocs publisher
|
||||
* @param config - A Backstage configuration
|
||||
@@ -37,7 +68,14 @@ export class Publisher {
|
||||
config: Config,
|
||||
options: PublisherFactory,
|
||||
): Promise<PublisherBase> {
|
||||
const { logger, discovery } = options;
|
||||
const { logger, discovery, customPublisher } = options;
|
||||
|
||||
const publishers = new Publisher();
|
||||
|
||||
if (customPublisher) {
|
||||
publishers.register('techdocs', customPublisher);
|
||||
return customPublisher;
|
||||
}
|
||||
|
||||
const publisherType = (config.getOptionalString(
|
||||
'techdocs.publisher.type',
|
||||
@@ -46,26 +84,51 @@ export class Publisher {
|
||||
switch (publisherType) {
|
||||
case 'googleGcs':
|
||||
logger.info('Creating Google Storage Bucket publisher for TechDocs');
|
||||
return GoogleGCSPublish.fromConfig(config, logger);
|
||||
publishers.register(
|
||||
publisherType,
|
||||
GoogleGCSPublish.fromConfig(config, logger),
|
||||
);
|
||||
break;
|
||||
case 'awsS3':
|
||||
logger.info('Creating AWS S3 Bucket publisher for TechDocs');
|
||||
return await AwsS3Publish.fromConfig(config, logger);
|
||||
publishers.register(
|
||||
publisherType,
|
||||
await AwsS3Publish.fromConfig(config, logger),
|
||||
);
|
||||
break;
|
||||
case 'azureBlobStorage':
|
||||
logger.info(
|
||||
'Creating Azure Blob Storage Container publisher for TechDocs',
|
||||
);
|
||||
return AzureBlobStoragePublish.fromConfig(config, logger);
|
||||
publishers.register(
|
||||
publisherType,
|
||||
AzureBlobStoragePublish.fromConfig(config, logger),
|
||||
);
|
||||
break;
|
||||
case 'openStackSwift':
|
||||
logger.info(
|
||||
'Creating OpenStack Swift Container publisher for TechDocs',
|
||||
);
|
||||
return OpenStackSwiftPublish.fromConfig(config, logger);
|
||||
publishers.register(
|
||||
publisherType,
|
||||
OpenStackSwiftPublish.fromConfig(config, logger),
|
||||
);
|
||||
break;
|
||||
case 'local':
|
||||
logger.info('Creating Local publisher for TechDocs');
|
||||
return LocalPublish.fromConfig(config, logger, discovery);
|
||||
publishers.register(
|
||||
publisherType,
|
||||
LocalPublish.fromConfig(config, logger, discovery),
|
||||
);
|
||||
break;
|
||||
default:
|
||||
logger.info('Creating Local publisher for TechDocs');
|
||||
return LocalPublish.fromConfig(config, logger, discovery);
|
||||
publishers.register(
|
||||
publisherType,
|
||||
LocalPublish.fromConfig(config, logger, discovery),
|
||||
);
|
||||
}
|
||||
|
||||
return publishers.get(config);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import { Entity, CompoundEntityRef } from '@backstage/catalog-model';
|
||||
import { PluginEndpointDiscovery } from '@backstage/backend-common';
|
||||
import { Logger } from 'winston';
|
||||
import express from 'express';
|
||||
import { Config } from '@backstage/config';
|
||||
|
||||
/**
|
||||
* Options for building publishers
|
||||
@@ -25,6 +26,7 @@ import express from 'express';
|
||||
export type PublisherFactory = {
|
||||
logger: Logger;
|
||||
discovery: PluginEndpointDiscovery;
|
||||
customPublisher?: PublisherBase | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -157,3 +159,12 @@ export interface PublisherBase {
|
||||
*/
|
||||
migrateDocsCase?(migrateRequest: MigrateRequest): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Definition for a TechDocs publisher builder
|
||||
* @public
|
||||
*/
|
||||
export type PublisherBuilder = {
|
||||
register(type: PublisherType, publisher: PublisherBase): void;
|
||||
get(config: Config): PublisherBase;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user