add publisher extension point

Signed-off-by: John Philip <jphilip@spotify.com>
This commit is contained in:
John Philip
2024-06-22 13:00:35 -04:00
parent 34f9882d12
commit c17cf4fd23
6 changed files with 144 additions and 10 deletions
+26 -1
View File
@@ -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',
});
+2
View File
@@ -27,7 +27,9 @@ export {
techdocsBuildsExtensionPoint,
techdocsGeneratorExtensionPoint,
techdocsPreparerExtensionPoint,
techdocsPublisherExtensionPoint,
type TechdocsBuildsExtensionPoint,
type TechdocsGeneratorExtensionPoint,
type TechdocsPreparerExtensionPoint,
type TechdocsPublisherExtensionPoint,
} from './extensions';
@@ -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,47 @@ 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 {
type CustomPublisherType = PublisherType | 'techdocs';
export class Publisher implements PublisherBuilder {
private publishers: Map<CustomPublisherType, PublisherBase> = new Map();
register(type: CustomPublisherType, 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 +70,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 +86,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;
};