Merge pull request #15695 from backstage/mob/compat
backend-common: added compatibility wrapper for legacy plugins
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/backend-common': patch
|
||||
---
|
||||
|
||||
Added `legacyPlugin` and the lower level `makeLegacyPlugin` wrappers that convert legacy plugins to the new backend system. This will be used to ease the future migration to the new backend system, but we discourage use of it for now.
|
||||
@@ -9,6 +9,7 @@
|
||||
import aws from 'aws-sdk';
|
||||
import { AwsS3Integration } from '@backstage/integration';
|
||||
import { AzureIntegration } from '@backstage/integration';
|
||||
import { BackendFeature } from '@backstage/backend-plugin-api';
|
||||
import { BitbucketCloudIntegration } from '@backstage/integration';
|
||||
import { BitbucketIntegration } from '@backstage/integration';
|
||||
import { BitbucketServerIntegration } from '@backstage/integration';
|
||||
@@ -16,6 +17,7 @@ import { CacheClient } from '@backstage/backend-plugin-api';
|
||||
import { CacheClientOptions } from '@backstage/backend-plugin-api';
|
||||
import { CacheClientSetOptions } from '@backstage/backend-plugin-api';
|
||||
import { Config } from '@backstage/config';
|
||||
import { ConfigService } from '@backstage/backend-plugin-api';
|
||||
import cors from 'cors';
|
||||
import Docker from 'dockerode';
|
||||
import { Duration } from 'luxon';
|
||||
@@ -26,6 +28,7 @@ import { GiteaIntegration } from '@backstage/integration';
|
||||
import { GithubCredentialsProvider } from '@backstage/integration';
|
||||
import { GithubIntegration } from '@backstage/integration';
|
||||
import { GitLabIntegration } from '@backstage/integration';
|
||||
import { IdentityService } from '@backstage/backend-plugin-api';
|
||||
import { isChildPath } from '@backstage/cli-common';
|
||||
import { Knex } from 'knex';
|
||||
import { KubeConfig } from '@kubernetes/client-node';
|
||||
@@ -33,6 +36,7 @@ import { LoadConfigOptionsRemote } from '@backstage/config-loader';
|
||||
import { Logger } from 'winston';
|
||||
import { LoggerService } from '@backstage/backend-plugin-api';
|
||||
import { MergeResult } from 'isomorphic-git';
|
||||
import { PermissionsService } from '@backstage/backend-plugin-api';
|
||||
import { CacheService as PluginCacheManager } from '@backstage/backend-plugin-api';
|
||||
import { DatabaseService as PluginDatabaseManager } from '@backstage/backend-plugin-api';
|
||||
import { DiscoveryService as PluginEndpointDiscovery } from '@backstage/backend-plugin-api';
|
||||
@@ -47,10 +51,12 @@ import { ReadUrlOptions } from '@backstage/backend-plugin-api';
|
||||
import { ReadUrlResponse } from '@backstage/backend-plugin-api';
|
||||
import { RequestHandler } from 'express';
|
||||
import { Router } from 'express';
|
||||
import { SchedulerService } from '@backstage/backend-plugin-api';
|
||||
import { SearchOptions } from '@backstage/backend-plugin-api';
|
||||
import { SearchResponse } from '@backstage/backend-plugin-api';
|
||||
import { SearchResponseFile } from '@backstage/backend-plugin-api';
|
||||
import { Server } from 'http';
|
||||
import { ServiceRef } from '@backstage/backend-plugin-api';
|
||||
import { TokenManagerService as TokenManager } from '@backstage/backend-plugin-api';
|
||||
import { TransportStreamOptions } from 'winston-transport';
|
||||
import { UrlReaderService as UrlReader } from '@backstage/backend-plugin-api';
|
||||
@@ -500,6 +506,35 @@ export type KubernetesContainerRunnerOptions = {
|
||||
timeoutMs?: number;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export type LegacyCreateRouter<TEnv> = (deps: TEnv) => Promise<RequestHandler>;
|
||||
|
||||
// @public
|
||||
export const legacyPlugin: (
|
||||
name: string,
|
||||
createRouterImport: Promise<{
|
||||
default: LegacyCreateRouter<
|
||||
TransformedEnv<
|
||||
{
|
||||
cache: PluginCacheManager;
|
||||
config: ConfigService;
|
||||
database: PluginDatabaseManager;
|
||||
discovery: PluginEndpointDiscovery;
|
||||
logger: LoggerService;
|
||||
permissions: PermissionsService;
|
||||
scheduler: SchedulerService;
|
||||
tokenManager: TokenManager;
|
||||
reader: UrlReader;
|
||||
identity: IdentityService;
|
||||
},
|
||||
{
|
||||
logger: (log: LoggerService) => Logger;
|
||||
}
|
||||
>
|
||||
>;
|
||||
}>,
|
||||
) => BackendFeature;
|
||||
|
||||
// @public
|
||||
export function loadBackendConfig(options: {
|
||||
logger: LoggerService;
|
||||
@@ -513,6 +548,24 @@ export function loggerToWinstonLogger(
|
||||
opts?: TransportStreamOptions,
|
||||
): Logger;
|
||||
|
||||
// @public
|
||||
export function makeLegacyPlugin<
|
||||
TEnv extends Record<string, unknown>,
|
||||
TEnvTransforms extends {
|
||||
[key in keyof TEnv]?: (dep: TEnv[key]) => unknown;
|
||||
},
|
||||
>(
|
||||
envMapping: {
|
||||
[key in keyof TEnv]: ServiceRef<TEnv[key]>;
|
||||
},
|
||||
envTransforms: TEnvTransforms,
|
||||
): (
|
||||
name: string,
|
||||
createRouterImport: Promise<{
|
||||
default: LegacyCreateRouter<TransformedEnv<TEnv, TEnvTransforms>>;
|
||||
}>,
|
||||
) => BackendFeature;
|
||||
|
||||
// @public
|
||||
export function notFoundHandler(): RequestHandler;
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
* @packageDocumentation
|
||||
*/
|
||||
|
||||
export { legacyPlugin, makeLegacyPlugin } from './legacy';
|
||||
export type { LegacyCreateRouter } from './legacy';
|
||||
export * from './cache';
|
||||
export { loadBackendConfig } from './config';
|
||||
export * from './context';
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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 {
|
||||
coreServices,
|
||||
createBackendPlugin,
|
||||
ServiceRef,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { RequestHandler } from 'express';
|
||||
import { loggerToWinstonLogger } from './logging';
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type LegacyCreateRouter<TEnv> = (deps: TEnv) => Promise<RequestHandler>;
|
||||
|
||||
/** @ignore */
|
||||
type TransformedEnv<
|
||||
TEnv extends Record<string, unknown>,
|
||||
TEnvTransforms extends { [key in keyof TEnv]?: (dep: TEnv[key]) => unknown },
|
||||
> = {
|
||||
[key in keyof TEnv]: TEnvTransforms[key] extends (dep: TEnv[key]) => infer R
|
||||
? R
|
||||
: TEnv[key];
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new custom plugin compatibility wrapper.
|
||||
*
|
||||
* @public
|
||||
* @remarks
|
||||
*
|
||||
* Usually you can use {@link legacyPlugin} directly instead, but you might
|
||||
* need to use this if you have customized the plugin environment in your backend.
|
||||
*/
|
||||
export function makeLegacyPlugin<
|
||||
TEnv extends Record<string, unknown>,
|
||||
TEnvTransforms extends { [key in keyof TEnv]?: (dep: TEnv[key]) => unknown },
|
||||
>(
|
||||
envMapping: { [key in keyof TEnv]: ServiceRef<TEnv[key]> },
|
||||
envTransforms: TEnvTransforms,
|
||||
) {
|
||||
return (
|
||||
name: string,
|
||||
createRouterImport: Promise<{
|
||||
default: LegacyCreateRouter<TransformedEnv<TEnv, TEnvTransforms>>;
|
||||
}>,
|
||||
) => {
|
||||
const compatPlugin = createBackendPlugin({
|
||||
id: name,
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: { ...envMapping, _router: coreServices.httpRouter },
|
||||
async init({ _router, ...envDeps }) {
|
||||
const { default: createRouter } = await createRouterImport;
|
||||
const pluginEnv = Object.fromEntries(
|
||||
Object.entries(envDeps).map(([key, dep]) => {
|
||||
const transform = envTransforms[key];
|
||||
if (transform) {
|
||||
return [key, transform(dep)];
|
||||
}
|
||||
return [key, dep];
|
||||
}),
|
||||
);
|
||||
const router = await createRouter(
|
||||
pluginEnv as TransformedEnv<TEnv, TEnvTransforms>,
|
||||
);
|
||||
_router.use(router);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
return compatPlugin();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to create a plugin from a legacy createRouter function and
|
||||
* register it with the http router based on the plugin id.
|
||||
*
|
||||
* @public
|
||||
* @remarks
|
||||
*
|
||||
* This is intended to be used by plugin authors to ease the transition to the
|
||||
* new backend system.
|
||||
*
|
||||
* @example
|
||||
*
|
||||
*```ts
|
||||
*backend.add(legacyPlugin('kafka', import('./plugins/kafka')));
|
||||
*```
|
||||
*/
|
||||
export const legacyPlugin = makeLegacyPlugin(
|
||||
{
|
||||
cache: coreServices.cache,
|
||||
config: coreServices.config,
|
||||
database: coreServices.database,
|
||||
discovery: coreServices.discovery,
|
||||
logger: coreServices.logger,
|
||||
permissions: coreServices.permissions,
|
||||
scheduler: coreServices.scheduler,
|
||||
tokenManager: coreServices.tokenManager,
|
||||
reader: coreServices.urlReader,
|
||||
identity: coreServices.identity,
|
||||
},
|
||||
{
|
||||
logger: log => loggerToWinstonLogger(log),
|
||||
},
|
||||
);
|
||||
Reference in New Issue
Block a user