techdocs-backend: Remove individual preparers and generators from app backend, to use factory methods
When a new Backstage app is setup, the techdocs backend file contains all the preparers (dir, github, gitlab, etc.) and same for generators. While this providers added customizibility, it comes with a cost of complexity in setting up the app backend. New preparers' updates would need users to update their app's techdocs backend file. Scaffolder backend has already moved to this proposed pattern.
This commit is contained in:
@@ -15,12 +15,8 @@
|
||||
*/
|
||||
import {
|
||||
createRouter,
|
||||
DirectoryPreparer,
|
||||
Preparers,
|
||||
Generators,
|
||||
TechdocsGenerator,
|
||||
CommonGitPreparer,
|
||||
UrlPreparer,
|
||||
Publisher,
|
||||
} from '@backstage/plugin-techdocs-backend';
|
||||
import { PluginEnvironment } from '../types';
|
||||
@@ -33,30 +29,25 @@ export default async function createPlugin({
|
||||
reader,
|
||||
}: PluginEnvironment) {
|
||||
// Preparers are responsible for fetching source files for documentation.
|
||||
const preparers = new Preparers();
|
||||
|
||||
const directoryPreparer = new DirectoryPreparer(logger);
|
||||
preparers.register('dir', directoryPreparer);
|
||||
|
||||
const commonGitPreparer = new CommonGitPreparer(logger);
|
||||
preparers.register('github', commonGitPreparer);
|
||||
preparers.register('gitlab', commonGitPreparer);
|
||||
preparers.register('azure/api', commonGitPreparer);
|
||||
|
||||
const urlPreparer = new UrlPreparer(reader, logger);
|
||||
preparers.register('url', urlPreparer);
|
||||
const preparers = await Preparers.fromConfig(config, {
|
||||
logger,
|
||||
reader,
|
||||
});
|
||||
|
||||
// Generators are used for generating documentation sites.
|
||||
const generators = new Generators();
|
||||
const techdocsGenerator = new TechdocsGenerator(logger, config);
|
||||
generators.register('techdocs', techdocsGenerator);
|
||||
const generators = await Generators.fromConfig(config, {
|
||||
logger,
|
||||
});
|
||||
|
||||
// Publishers are used for
|
||||
// Publisher is used for
|
||||
// 1. Publishing generated files to storage
|
||||
// 2. Fetching files from storage and passing them to TechDocs frontend.
|
||||
const publisher = Publisher.fromConfig(config, logger, discovery);
|
||||
const publisher = await Publisher.fromConfig(config, {
|
||||
logger,
|
||||
discovery,
|
||||
});
|
||||
|
||||
// Docker client used by the generators.
|
||||
// Docker client (conditionally) used by the generators, based on techdocs.generators config.
|
||||
const dockerClient = new Docker();
|
||||
|
||||
return await createRouter({
|
||||
|
||||
@@ -14,18 +14,32 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Logger } from 'winston';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { Config } from '@backstage/config';
|
||||
import { TechdocsGenerator } from '.';
|
||||
import {
|
||||
GeneratorBase,
|
||||
SupportedGeneratorKey,
|
||||
GeneratorBuilder,
|
||||
} from './types';
|
||||
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { getGeneratorKey } from './helpers';
|
||||
|
||||
export class Generators implements GeneratorBuilder {
|
||||
private generatorMap = new Map<SupportedGeneratorKey, GeneratorBase>();
|
||||
|
||||
static async fromConfig(
|
||||
config: Config,
|
||||
{ logger }: { logger: Logger },
|
||||
): Promise<GeneratorBuilder> {
|
||||
const generators = new Generators();
|
||||
|
||||
const techdocsGenerator = new TechdocsGenerator(logger, config);
|
||||
generators.register('techdocs', techdocsGenerator);
|
||||
|
||||
return generators;
|
||||
}
|
||||
|
||||
register(generatorKey: SupportedGeneratorKey, generator: GeneratorBase) {
|
||||
this.generatorMap.set(generatorKey, generator);
|
||||
}
|
||||
|
||||
@@ -13,14 +13,45 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { PreparerBase, RemoteProtocol, PreparerBuilder } from './types';
|
||||
import { Logger } from 'winston';
|
||||
import { UrlReader } from '@backstage/backend-common';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { Config } from '@backstage/config';
|
||||
import { DirectoryPreparer, CommonGitPreparer, UrlPreparer } from '.';
|
||||
import { PreparerBase, RemoteProtocol, PreparerBuilder } from './types';
|
||||
import { parseReferenceAnnotation } from '../../helpers';
|
||||
|
||||
type factoryOptions = {
|
||||
logger: Logger;
|
||||
reader: UrlReader;
|
||||
};
|
||||
|
||||
export class Preparers implements PreparerBuilder {
|
||||
private preparerMap = new Map<RemoteProtocol, PreparerBase>();
|
||||
|
||||
static async fromConfig(
|
||||
// @ts-ignore
|
||||
// Config not used now, but will be used in urlPreparer when it starts using
|
||||
// @backstage/integration to get the tokens for providers.
|
||||
config: Config,
|
||||
{ logger, reader }: factoryOptions,
|
||||
): Promise<PreparerBuilder> {
|
||||
const preparers = new Preparers();
|
||||
|
||||
const directoryPreparer = new DirectoryPreparer(logger);
|
||||
preparers.register('dir', directoryPreparer);
|
||||
|
||||
const commonGitPreparer = new CommonGitPreparer(logger);
|
||||
preparers.register('github', commonGitPreparer);
|
||||
preparers.register('gitlab', commonGitPreparer);
|
||||
preparers.register('azure/api', commonGitPreparer);
|
||||
|
||||
const urlPreparer = new UrlPreparer(reader, logger);
|
||||
preparers.register('url', urlPreparer);
|
||||
|
||||
return preparers;
|
||||
}
|
||||
|
||||
register(protocol: RemoteProtocol, preparer: PreparerBase) {
|
||||
this.preparerMap.set(protocol, preparer);
|
||||
}
|
||||
|
||||
@@ -23,24 +23,27 @@ import { LocalPublish } from './local';
|
||||
import { GoogleGCSPublish } from './googleStorage';
|
||||
|
||||
const logger = getVoidLogger();
|
||||
const testDiscovery: jest.Mocked<PluginEndpointDiscovery> = {
|
||||
const discovery: jest.Mocked<PluginEndpointDiscovery> = {
|
||||
getBaseUrl: jest.fn().mockResolvedValueOnce('http://localhost:7000'),
|
||||
getExternalBaseUrl: jest.fn(),
|
||||
};
|
||||
|
||||
describe('Publisher', () => {
|
||||
it('should create local publisher by default', () => {
|
||||
it('should create local publisher by default', async () => {
|
||||
const mockConfig = new ConfigReader({
|
||||
techdocs: {
|
||||
requestUrl: 'http://localhost:7000',
|
||||
},
|
||||
});
|
||||
|
||||
const publisher = Publisher.fromConfig(mockConfig, logger, testDiscovery);
|
||||
const publisher = await Publisher.fromConfig(mockConfig, {
|
||||
logger,
|
||||
discovery,
|
||||
});
|
||||
expect(publisher).toBeInstanceOf(LocalPublish);
|
||||
});
|
||||
|
||||
it('should create local publisher from config', () => {
|
||||
it('should create local publisher from config', async () => {
|
||||
const mockConfig = new ConfigReader({
|
||||
techdocs: {
|
||||
requestUrl: 'http://localhost:7000',
|
||||
@@ -50,11 +53,14 @@ describe('Publisher', () => {
|
||||
},
|
||||
});
|
||||
|
||||
const publisher = Publisher.fromConfig(mockConfig, logger, testDiscovery);
|
||||
const publisher = await Publisher.fromConfig(mockConfig, {
|
||||
logger,
|
||||
discovery,
|
||||
});
|
||||
expect(publisher).toBeInstanceOf(LocalPublish);
|
||||
});
|
||||
|
||||
it('should create google gcs publisher from config', () => {
|
||||
it('should create google gcs publisher from config', async () => {
|
||||
const mockConfig = new ConfigReader({
|
||||
techdocs: {
|
||||
requestUrl: 'http://localhost:7000',
|
||||
@@ -69,7 +75,10 @@ describe('Publisher', () => {
|
||||
},
|
||||
});
|
||||
|
||||
const publisher = Publisher.fromConfig(mockConfig, logger, testDiscovery);
|
||||
const publisher = await Publisher.fromConfig(mockConfig, {
|
||||
logger,
|
||||
discovery,
|
||||
});
|
||||
expect(publisher).toBeInstanceOf(GoogleGCSPublish);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -21,16 +21,20 @@ import { PublisherType, PublisherBase } from './types';
|
||||
import { LocalPublish } from './local';
|
||||
import { GoogleGCSPublish } from './googleStorage';
|
||||
|
||||
type factoryOptions = {
|
||||
logger: Logger;
|
||||
discovery: PluginEndpointDiscovery;
|
||||
};
|
||||
|
||||
/**
|
||||
* Factory class to create a TechDocs publisher based on defined publisher type in app config.
|
||||
* Uses `techdocs.publisher.type`.
|
||||
*/
|
||||
export class Publisher {
|
||||
static fromConfig(
|
||||
static async fromConfig(
|
||||
config: Config,
|
||||
logger: Logger,
|
||||
discovery: PluginEndpointDiscovery,
|
||||
): PublisherBase {
|
||||
{ logger, discovery }: factoryOptions,
|
||||
): Promise<PublisherBase> {
|
||||
const publisherType = (config.getOptionalString(
|
||||
'techdocs.publisher.type',
|
||||
) ?? 'local') as PublisherType;
|
||||
|
||||
@@ -59,7 +59,7 @@ export async function startStandaloneServer(
|
||||
const techdocsGenerator = new TechdocsGenerator(logger, config);
|
||||
generators.register('techdocs', techdocsGenerator);
|
||||
|
||||
const publisher = Publisher.fromConfig(config, logger, discovery);
|
||||
const publisher = await Publisher.fromConfig(config, { logger, discovery });
|
||||
|
||||
const dockerClient = new Docker();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user