TechDocs: Refactor Publisher to pave way for external publishers
This commit is contained in:
@@ -20,12 +20,7 @@ import Knex from 'knex';
|
||||
import fetch from 'cross-fetch';
|
||||
import { Config } from '@backstage/config';
|
||||
import Docker from 'dockerode';
|
||||
import {
|
||||
GeneratorBuilder,
|
||||
PreparerBuilder,
|
||||
PublisherBase,
|
||||
LocalPublish,
|
||||
} from '../techdocs';
|
||||
import { GeneratorBuilder, PreparerBuilder, PublisherBase } from '../techdocs';
|
||||
import {
|
||||
PluginEndpointDiscovery,
|
||||
resolvePackagePath,
|
||||
@@ -63,7 +58,7 @@ export async function createRouter({
|
||||
|
||||
router.get('/metadata/techdocs/*', async (req, res) => {
|
||||
let storageUrl = config.getString('techdocs.storageUrl');
|
||||
if (publisher instanceof LocalPublish) {
|
||||
if (publisher.isLocalPublisher()) {
|
||||
storageUrl = new URL(
|
||||
new URL(storageUrl).pathname,
|
||||
await discovery.getBaseUrl('techdocs'),
|
||||
@@ -140,7 +135,7 @@ export async function createRouter({
|
||||
res.redirect(`${storageUrl}${req.path.replace('/docs', '')}`);
|
||||
});
|
||||
|
||||
if (publisher instanceof LocalPublish) {
|
||||
if (publisher.isLocalPublisher()) {
|
||||
router.use('/static/docs', express.static(staticDocsDir));
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
DirectoryPreparer,
|
||||
Generators,
|
||||
TechdocsGenerator,
|
||||
LocalPublish,
|
||||
Publisher,
|
||||
} from '../techdocs';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
|
||||
@@ -41,7 +41,18 @@ export async function startStandaloneServer(
|
||||
options: ServerOptions,
|
||||
): Promise<Server> {
|
||||
const logger = options.logger.child({ service: 'techdocs-backend' });
|
||||
const config = ConfigReader.fromConfigs([]);
|
||||
const config = ConfigReader.fromConfigs([
|
||||
{
|
||||
context: '',
|
||||
data: {
|
||||
techdocs: {
|
||||
publisher: {
|
||||
type: 'local',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
]);
|
||||
const discovery = SingleHostDiscovery.fromConfig(config);
|
||||
|
||||
logger.debug('Creating application...');
|
||||
@@ -53,7 +64,7 @@ export async function startStandaloneServer(
|
||||
const techdocsGenerator = new TechdocsGenerator(logger, config);
|
||||
generators.register('techdocs', techdocsGenerator);
|
||||
|
||||
const publisher = new LocalPublish(logger, discovery);
|
||||
const publisher = new Publisher(logger, config, discovery);
|
||||
|
||||
const dockerClient = new Docker();
|
||||
|
||||
|
||||
@@ -13,5 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { LocalPublish } from './local';
|
||||
export type { PublisherBase } from './types';
|
||||
export { Publisher } from './publish';
|
||||
export type { PublisherBase } from './publish';
|
||||
export type { PublisherType } from './types';
|
||||
|
||||
@@ -16,13 +16,38 @@
|
||||
import fs from 'fs-extra';
|
||||
import { Logger } from 'winston';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { PublisherBase } from './types';
|
||||
import {
|
||||
resolvePackagePath,
|
||||
PluginEndpointDiscovery,
|
||||
} from '@backstage/backend-common';
|
||||
|
||||
export class LocalPublish implements PublisherBase {
|
||||
export type LocalPublishParams = {
|
||||
entity: Entity;
|
||||
directory: string;
|
||||
};
|
||||
|
||||
export type LocalPublishReturn =
|
||||
| Promise<{ remoteUrl: string }>
|
||||
| { remoteUrl: string };
|
||||
|
||||
/**
|
||||
* Type for the local publisher which uses local filesystem to store the generated static files.
|
||||
*
|
||||
* It uses a directory called "static" at the root of techdocs-backend plugin.
|
||||
*/
|
||||
export interface LocalPublisher {
|
||||
/**
|
||||
* Store the generated files inside a static folder in local filesystem.
|
||||
*
|
||||
* @param {LocalPublishParams} opts Object containing the entity from the service
|
||||
* catalog, and the directory that contains the generated static files from TechDocs.
|
||||
* @returns {LocalPublishReturn} Either a promise or an object with `remoteUrl` which is the URL
|
||||
* which serves files from the local publisher's static directory.
|
||||
*/
|
||||
publish(opts: LocalPublishParams): LocalPublishReturn;
|
||||
}
|
||||
|
||||
export class LocalPublish {
|
||||
private readonly logger: Logger;
|
||||
private readonly discovery: PluginEndpointDiscovery;
|
||||
|
||||
@@ -31,17 +56,7 @@ export class LocalPublish implements PublisherBase {
|
||||
this.discovery = discovery;
|
||||
}
|
||||
|
||||
publish({
|
||||
entity,
|
||||
directory,
|
||||
}: {
|
||||
entity: Entity;
|
||||
directory: string;
|
||||
}):
|
||||
| Promise<{
|
||||
remoteUrl: string;
|
||||
}>
|
||||
| { remoteUrl: string } {
|
||||
publish({ entity, directory }: LocalPublishParams): LocalPublishReturn {
|
||||
const entityNamespace = entity.metadata.namespace ?? 'default';
|
||||
|
||||
const publishDir = resolvePackagePath(
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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 { Logger } from 'winston';
|
||||
import { Config } from '@backstage/config';
|
||||
import { PluginEndpointDiscovery } from '@backstage/backend-common';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { PublisherType } from './types';
|
||||
import { LocalPublish } from './local';
|
||||
|
||||
export type PublisherBaseParams = {
|
||||
entity: Entity;
|
||||
directory: string;
|
||||
};
|
||||
|
||||
export type PublisherBaseReturn =
|
||||
| Promise<{ remoteUrl: string }>
|
||||
| { remoteUrl: string };
|
||||
|
||||
/**
|
||||
* Type for the publisher instance registered with backend which manages publishing of the
|
||||
* generated static files after the prepare and generate steps of TechDocs.
|
||||
*
|
||||
* Depending upon the value of techdocs.publisher.type in app config, this instance creates
|
||||
* and uses a publisher of the particular type i.e. local, google_gcs, aws_s3, etc. It defaults
|
||||
* to use the local publisher.
|
||||
*/
|
||||
export interface PublisherBase {
|
||||
/**
|
||||
* Invoke the app's configured publisher's publish method.
|
||||
*
|
||||
* @param {PublisherBaseParams} opts Object containing the entity from the service
|
||||
* catalog, and the directory that contains the generated static files from TechDocs.
|
||||
*/
|
||||
publish(opts: PublisherBaseParams): PublisherBaseReturn;
|
||||
|
||||
/**
|
||||
* Return true if local filesystem is being used to store generated files for TechDocs.
|
||||
*/
|
||||
isLocalPublisher(): boolean;
|
||||
|
||||
/**
|
||||
* Return true if an external cloud storage (GCS, S3, SFTP server, etc.) is being used to
|
||||
* store generated files for TechDocs.
|
||||
*/
|
||||
isExternalPublisher(): boolean;
|
||||
}
|
||||
|
||||
export class Publisher implements PublisherBase {
|
||||
private readonly logger: Logger;
|
||||
private readonly config: Config;
|
||||
private readonly discovery: PluginEndpointDiscovery;
|
||||
private readonly publisherType: PublisherType;
|
||||
private readonly publisher: any;
|
||||
|
||||
constructor(
|
||||
logger: Logger,
|
||||
config: Config,
|
||||
discovery: PluginEndpointDiscovery,
|
||||
) {
|
||||
this.logger = logger;
|
||||
this.config = config;
|
||||
this.discovery = discovery;
|
||||
|
||||
this.publisherType =
|
||||
(this.config.getOptionalString(
|
||||
'techdocs.publisher.type',
|
||||
) as PublisherType) ?? 'local';
|
||||
|
||||
switch (this.publisherType) {
|
||||
case 'google_gcs':
|
||||
this.logger.info(
|
||||
'Creating Google Storage Bucket publisher for TechDocs',
|
||||
);
|
||||
this.publisher = new LocalPublish(this.logger, this.discovery);
|
||||
break;
|
||||
case 'local':
|
||||
this.logger.info('Creating Local publisher for TechDocs');
|
||||
this.publisher = new LocalPublish(this.logger, this.discovery);
|
||||
break;
|
||||
default:
|
||||
this.logger.info('Creating Local publisher for TechDocs');
|
||||
this.publisher = new LocalPublish(this.logger, this.discovery);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
publish({ entity, directory }: PublisherBaseParams): PublisherBaseReturn {
|
||||
return this.publisher.publish({ entity, directory });
|
||||
}
|
||||
|
||||
isLocalPublisher(): boolean {
|
||||
return this.publisherType === 'local';
|
||||
}
|
||||
|
||||
isExternalPublisher(): boolean {
|
||||
return this.publisherType !== 'local';
|
||||
}
|
||||
}
|
||||
@@ -13,20 +13,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
|
||||
/**
|
||||
* Publisher is in charge of taking a folder created by
|
||||
* the builder, and pushing it to storage
|
||||
* Key for all the different types of TechDocs publishers available.
|
||||
*/
|
||||
export type PublisherBase = {
|
||||
/**
|
||||
*
|
||||
* @param opts object containing the entity from the service
|
||||
* catalog, and the directory that has been generated
|
||||
*/
|
||||
publish(opts: {
|
||||
entity: Entity;
|
||||
directory: string;
|
||||
}): Promise<{ remoteUrl: string }> | { remoteUrl: string };
|
||||
};
|
||||
export type PublisherType = 'local' | 'google_gcs';
|
||||
|
||||
export interface ExternalPublisher {}
|
||||
|
||||
Reference in New Issue
Block a user