Merge pull request #15720 from backstage/rugvip/refactory

backend-app-api: switch factory functions to be defined with options as a top-level callback
This commit is contained in:
Patrik Oldsberg
2023-01-13 16:18:41 +01:00
committed by GitHub
32 changed files with 410 additions and 390 deletions
+8
View File
@@ -0,0 +1,8 @@
---
'@backstage/plugin-catalog-backend-module-incremental-ingestion': patch
'@backstage/plugin-scaffolder-backend': patch
'@backstage/backend-app-api': patch
'@backstage/plugin-app-backend': patch
---
Internal refactor to match new options pattern in the experimental backend system.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-plugin-api': minor
---
Updated all factory function creators to accept options as a top-level callback rather than extra parameter to the main factory function.
+16 -44
View File
@@ -46,14 +46,10 @@ export interface Backend {
}
// @public (undocumented)
export const cacheFactory: (
options?: undefined,
) => ServiceFactory<PluginCacheManager>;
export const cacheFactory: () => ServiceFactory<PluginCacheManager>;
// @public (undocumented)
export const configFactory: (
options?: undefined,
) => ServiceFactory<ConfigService>;
export const configFactory: () => ServiceFactory<ConfigService>;
// @public
export function createHttpServer(
@@ -76,9 +72,7 @@ export interface CreateSpecializedBackendOptions {
}
// @public (undocumented)
export const databaseFactory: (
options?: undefined,
) => ServiceFactory<PluginDatabaseManager>;
export const databaseFactory: () => ServiceFactory<PluginDatabaseManager>;
// @public
export class DefaultRootHttpRouter implements RootHttpRouterService {
@@ -96,9 +90,7 @@ export interface DefaultRootHttpRouterOptions {
}
// @public (undocumented)
export const discoveryFactory: (
options?: undefined,
) => ServiceFactory<PluginEndpointDiscovery>;
export const discoveryFactory: () => ServiceFactory<PluginEndpointDiscovery>;
// @public
export interface ExtendedHttpServer extends http.Server {
@@ -116,9 +108,9 @@ export const httpRouterFactory: (
) => ServiceFactory<HttpRouterService>;
// @public (undocumented)
export type HttpRouterFactoryOptions = {
export interface HttpRouterFactoryOptions {
getPath(pluginId: string): string;
};
}
// @public
export type HttpServerCertificateOptions =
@@ -144,9 +136,7 @@ export type HttpServerOptions = {
};
// @public (undocumented)
export const identityFactory: (
options?: IdentityFactoryOptions | undefined,
) => ServiceFactory<IdentityService>;
export const identityFactory: () => ServiceFactory<IdentityService>;
// @public
export type IdentityFactoryOptions = {
@@ -155,14 +145,10 @@ export type IdentityFactoryOptions = {
};
// @public
export const lifecycleFactory: (
options?: undefined,
) => ServiceFactory<LifecycleService>;
export const lifecycleFactory: () => ServiceFactory<LifecycleService>;
// @public (undocumented)
export const loggerFactory: (
options?: undefined,
) => ServiceFactory<LoggerService>;
export const loggerFactory: () => ServiceFactory<LoggerService>;
// @public
export class MiddlewareFactory {
@@ -190,9 +176,7 @@ export interface MiddlewareFactoryOptions {
}
// @public (undocumented)
export const permissionsFactory: (
options?: undefined,
) => ServiceFactory<PermissionsService>;
export const permissionsFactory: () => ServiceFactory<PermissionsService>;
// @public
export function readCorsOptions(config?: Config): CorsOptions;
@@ -220,9 +204,7 @@ export interface RootHttpRouterConfigureOptions {
}
// @public (undocumented)
export const rootHttpRouterFactory: (
options?: RootHttpRouterFactoryOptions | undefined,
) => ServiceFactory<RootHttpRouterService>;
export const rootHttpRouterFactory: () => ServiceFactory<RootHttpRouterService>;
// @public (undocumented)
export type RootHttpRouterFactoryOptions = {
@@ -231,19 +213,13 @@ export type RootHttpRouterFactoryOptions = {
};
// @public
export const rootLifecycleFactory: (
options?: undefined,
) => ServiceFactory<RootLifecycleService>;
export const rootLifecycleFactory: () => ServiceFactory<RootLifecycleService>;
// @public (undocumented)
export const rootLoggerFactory: (
options?: undefined,
) => ServiceFactory<RootLoggerService>;
export const rootLoggerFactory: () => ServiceFactory<RootLoggerService>;
// @public (undocumented)
export const schedulerFactory: (
options?: undefined,
) => ServiceFactory<SchedulerService>;
export const schedulerFactory: () => ServiceFactory<SchedulerService>;
// @public (undocumented)
export type ServiceOrExtensionPoint<T = unknown> =
@@ -251,12 +227,8 @@ export type ServiceOrExtensionPoint<T = unknown> =
| ServiceRef<T>;
// @public (undocumented)
export const tokenManagerFactory: (
options?: undefined,
) => ServiceFactory<TokenManagerService>;
export const tokenManagerFactory: () => ServiceFactory<TokenManagerService>;
// @public (undocumented)
export const urlReaderFactory: (
options?: undefined,
) => ServiceFactory<UrlReader>;
export const urlReaderFactory: () => ServiceFactory<UrlReader>;
```
@@ -23,30 +23,32 @@ import { Handler } from 'express';
/**
* @public
*/
export type HttpRouterFactoryOptions = {
export interface HttpRouterFactoryOptions {
/**
* A callback used to generate the path for each plugin, defaults to `/api/{pluginId}`.
*/
getPath(pluginId: string): string;
};
}
/** @public */
export const httpRouterFactory = createServiceFactory({
service: coreServices.httpRouter,
deps: {
plugin: coreServices.pluginMetadata,
rootHttpRouter: coreServices.rootHttpRouter,
},
async factory({ rootHttpRouter }, options?: HttpRouterFactoryOptions) {
const getPath = options?.getPath ?? (id => `/api/${id}`);
export const httpRouterFactory = createServiceFactory(
(options?: HttpRouterFactoryOptions) => ({
service: coreServices.httpRouter,
deps: {
plugin: coreServices.pluginMetadata,
rootHttpRouter: coreServices.rootHttpRouter,
},
async factory({ rootHttpRouter }) {
const getPath = options?.getPath ?? (id => `/api/${id}`);
return async ({ plugin }) => {
const path = getPath(plugin.getId());
return {
use(handler: Handler) {
rootHttpRouter.use(path, handler);
},
return async ({ plugin }) => {
const path = getPath(plugin.getId());
return {
use(handler: Handler) {
rootHttpRouter.use(path, handler);
},
};
};
};
},
});
},
}),
);
@@ -143,7 +143,7 @@ describe('ServiceRegistry', () => {
const factory = createServiceFactory({
service: ref1,
deps: { rootDep: ref2 },
async factory({ rootDep }) {
factory: async ({ rootDep }) => {
return async () => ({ x: rootDep.x });
},
});
+16 -15
View File
@@ -23,7 +23,7 @@ export interface BackendFeature {
}
// @public (undocumented)
export interface BackendModuleConfig<TOptions> {
export interface BackendModuleConfig {
// (undocumented)
moduleId: string;
// (undocumented)
@@ -31,16 +31,15 @@ export interface BackendModuleConfig<TOptions> {
// (undocumented)
register(
reg: Omit<BackendRegistrationPoints, 'registerExtensionPoint'>,
options: TOptions,
): void;
}
// @public (undocumented)
export interface BackendPluginConfig<TOptions> {
export interface BackendPluginConfig {
// (undocumented)
id: string;
// (undocumented)
register(reg: BackendRegistrationPoints, options: TOptions): void;
register(reg: BackendRegistrationPoints): void;
}
// @public (undocumented)
@@ -113,14 +112,14 @@ export namespace coreServices {
}
// @public
export function createBackendModule<TOptions extends MaybeOptions = undefined>(
config: BackendModuleConfig<TOptions>,
): FactoryFunctionWithOptions<BackendFeature, TOptions>;
export function createBackendModule<TOptions extends [options?: object] = []>(
config: BackendModuleConfig | ((...params: TOptions) => BackendModuleConfig),
): (...params: TOptions) => BackendFeature;
// @public (undocumented)
export function createBackendPlugin<TOptions extends MaybeOptions = undefined>(
config: BackendPluginConfig<TOptions>,
): FactoryFunctionWithOptions<BackendFeature, TOptions>;
export function createBackendPlugin<TOptions extends [options?: object] = []>(
config: BackendPluginConfig | ((...params: TOptions) => BackendPluginConfig),
): (...params: TOptions) => BackendFeature;
// @public (undocumented)
export function createExtensionPoint<T>(
@@ -135,10 +134,14 @@ export function createServiceFactory<
TDeps extends {
[name in string]: ServiceRef<unknown>;
},
TOpts extends MaybeOptions = undefined,
TOpts extends [options?: object] = [],
>(
config: ServiceFactoryConfig<TService, TScope, TImpl, TDeps, TOpts>,
): FactoryFunctionWithOptions<ServiceFactory<TService>, TOpts>;
config:
| ServiceFactoryConfig<TService, TScope, TImpl, TDeps>
| ((
...options: TOpts
) => ServiceFactoryConfig<TService, TScope, TImpl, TDeps>),
): (...params: TOpts) => ServiceFactory<TService>;
// @public
export function createServiceRef<TService>(
@@ -337,14 +340,12 @@ export interface ServiceFactoryConfig<
TDeps extends {
[name in string]: ServiceRef<unknown>;
},
TOpts extends MaybeOptions = undefined,
> {
// (undocumented)
deps: TDeps;
// (undocumented)
factory(
deps: ServiceRefsToInstances<TDeps, 'root'>,
options: TOpts,
): TScope extends 'root'
? Promise<TImpl>
: Promise<(deps: ServiceRefsToInstances<TDeps>) => Promise<TImpl>>;
@@ -16,9 +16,12 @@
import { createServiceFactory, createServiceRef } from './types';
const ref = createServiceRef<string>({ id: 'x' });
const rootDep = createServiceRef<number>({ id: 'y', scope: 'root' });
const pluginDep = createServiceRef<boolean>({ id: 'z' });
describe('createServiceFactory', () => {
it('should create a meta factory with no options', () => {
const ref = createServiceRef<string>({ id: 'x' });
const metaFactory = createServiceFactory({
service: ref,
deps: {},
@@ -37,19 +40,19 @@ describe('createServiceFactory', () => {
metaFactory({ x: 1 });
// @ts-expect-error
metaFactory(null);
// @ts-expect-error
metaFactory(undefined);
metaFactory();
});
it('should create a meta factory with optional options', () => {
const ref = createServiceRef<string>({ id: 'x' });
const metaFactory = createServiceFactory({
const metaFactory = createServiceFactory((_opts?: { x: number }) => ({
service: ref,
deps: {},
async factory(_deps, _opts?: { x: number }) {
async factory() {
return async () => 'x';
},
});
}));
expect(metaFactory).toEqual(expect.any(Function));
// @ts-expect-error
@@ -66,14 +69,13 @@ describe('createServiceFactory', () => {
});
it('should create a meta factory with required options', () => {
const ref = createServiceRef<string>({ id: 'x' });
const metaFactory = createServiceFactory({
const metaFactory = createServiceFactory((_opts: { x: number }) => ({
service: ref,
deps: {},
async factory(_deps, _opts: { x: number }) {
async factory() {
return async () => 'x';
},
});
}));
expect(metaFactory).toEqual(expect.any(Function));
// @ts-expect-error
@@ -95,14 +97,13 @@ describe('createServiceFactory', () => {
interface TestOptions {
x: number;
}
const ref = createServiceRef<string>({ id: 'x' });
const metaFactory = createServiceFactory({
const metaFactory = createServiceFactory((_opts?: TestOptions) => ({
service: ref,
deps: {},
async factory(_deps, _opts?: TestOptions) {
async factory() {
return async () => 'x';
},
});
}));
expect(metaFactory).toEqual(expect.any(Function));
// @ts-expect-error
@@ -122,14 +123,13 @@ describe('createServiceFactory', () => {
interface TestOptions {
x: number;
}
const ref = createServiceRef<string>({ id: 'x' });
const metaFactory = createServiceFactory({
const metaFactory = createServiceFactory((_opts: TestOptions) => ({
service: ref,
deps: {},
async factory(_deps, _opts: TestOptions) {
async factory() {
return async () => 'x';
},
});
}));
expect(metaFactory).toEqual(expect.any(Function));
// @ts-expect-error
@@ -147,80 +147,163 @@ describe('createServiceFactory', () => {
metaFactory();
});
it('should only allow objects as options', () => {
const ref = createServiceRef<string>({ id: 'x' });
const metaFactory = createServiceFactory({
it('should create factory with required options and dependencies', () => {
interface TestOptions {
x: number;
}
function unused(..._any: any[]) {}
const metaFactory = createServiceFactory((_opts: TestOptions) => ({
service: ref,
deps: {},
// @ts-expect-error
async factory(_deps, _opts: string) {
return async () => 'x';
deps: {
root: rootDep,
plugin: pluginDep,
},
});
async factory({ root }) {
const root1: number = root;
// @ts-expect-error
const root2: string = root;
return async ({ plugin }) => {
const plugin3: boolean = plugin;
// @ts-expect-error
const plugin4: number = plugin;
unused(root1, root2, plugin3, plugin4);
return 'x';
};
},
}));
expect(metaFactory).toEqual(expect.any(Function));
createServiceFactory({
// @ts-expect-error
metaFactory('string');
// @ts-expect-error
metaFactory({});
metaFactory({ x: 1 });
// @ts-expect-error
metaFactory({ x: 1, y: 2 });
// @ts-expect-error
metaFactory(null);
// @ts-expect-error
metaFactory(undefined);
// @ts-expect-error
metaFactory();
});
it('should create factory with optional options and dependencies', () => {
interface TestOptions {
x: number;
}
function unused(..._any: any[]) {}
const metaFactory = createServiceFactory((_opts?: TestOptions) => ({
service: ref,
deps: {
root: rootDep,
plugin: pluginDep,
},
async factory({ root }) {
const root1: number = root;
// @ts-expect-error
const root2: string = root;
return async ({ plugin }) => {
const plugin3: boolean = plugin;
// @ts-expect-error
const plugin4: number = plugin;
unused(root1, root2, plugin3, plugin4);
return 'x';
};
},
}));
expect(metaFactory).toEqual(expect.any(Function));
// @ts-expect-error
metaFactory('string');
// @ts-expect-error
metaFactory({});
metaFactory({ x: 1 });
// @ts-expect-error
metaFactory({ x: 1, y: 2 });
// @ts-expect-error
metaFactory(null);
metaFactory(undefined);
metaFactory();
});
it('should only allow objects as options', () => {
// @ts-expect-error
const metaFactory = createServiceFactory((_opts: string) => ({
service: ref,
deps: {},
// @ts-expect-error
async factory(_deps, _opts: number) {
async factory() {
return async () => 'x';
},
});
createServiceFactory({
}));
expect(metaFactory).toEqual(expect.any(Function));
// @ts-expect-error
createServiceFactory((_opts: number) => ({
service: ref,
deps: {},
// @ts-expect-error
async factory(_deps, _opts: symbol) {
async factory() {
return async () => 'x';
},
});
createServiceFactory({
}));
// @ts-expect-error
createServiceFactory((_opts: symbol) => ({
service: ref,
deps: {},
// @ts-expect-error
async factory(_deps, _opts: bigint) {
async factory() {
return async () => 'x';
},
});
createServiceFactory({
}));
// @ts-expect-error
createServiceFactory((_opts: bigint) => ({
service: ref,
deps: {},
// @ts-expect-error
async factory(_deps, _opts: 'string') {
async factory() {
return async () => 'x';
},
});
createServiceFactory({
}));
// @ts-expect-error
createServiceFactory((_opts: 'string') => ({
service: ref,
deps: {},
// @ts-expect-error
async factory(_deps, _opts: Array) {
async factory() {
return async () => 'x';
},
});
createServiceFactory({
}));
// @ts-expect-error
createServiceFactory((_opts: Array) => ({
service: ref,
deps: {},
// @ts-expect-error
async factory(_deps, _opts: Map) {
async factory() {
return async () => 'x';
},
});
createServiceFactory({
}));
// @ts-expect-error
createServiceFactory((_opts: Map) => ({
service: ref,
deps: {},
// @ts-expect-error
async factory(_deps, _opts: Set) {
async factory() {
return async () => 'x';
},
});
createServiceFactory({
}));
// @ts-expect-error
createServiceFactory((_opts: Set) => ({
service: ref,
deps: {},
// @ts-expect-error
async factory(_deps, _opts: null) {
async factory() {
return async () => 'x';
},
});
}));
// @ts-expect-error
createServiceFactory((_opts: null) => ({
service: ref,
deps: {},
async factory() {
return async () => 'x';
},
}));
});
});
@@ -14,8 +14,6 @@
* limitations under the License.
*/
import { FactoryFunctionWithOptions, MaybeOptions } from '../../types';
/**
* TODO
*
@@ -133,9 +131,7 @@ type ServiceRefsToInstances<
T extends { [key in string]: ServiceRef<unknown> },
TScope extends 'root' | 'plugin' = 'root' | 'plugin',
> = {
[name in {
[key in keyof T]: T[key] extends ServiceRef<unknown, TScope> ? key : never;
}[keyof T]]: T[name] extends ServiceRef<infer TImpl> ? TImpl : never;
[key in keyof T as T[key]['scope'] extends TScope ? key : never]: T[key]['T'];
};
/** @public */
@@ -144,13 +140,11 @@ export interface ServiceFactoryConfig<
TScope extends 'root' | 'plugin',
TImpl extends TService,
TDeps extends { [name in string]: ServiceRef<unknown> },
TOpts extends MaybeOptions = undefined,
> {
service: ServiceRef<TService, TScope>;
deps: TDeps;
factory(
deps: ServiceRefsToInstances<TDeps, 'root'>,
options: TOpts,
): TScope extends 'root'
? Promise<TImpl>
: Promise<(deps: ServiceRefsToInstances<TDeps>) => Promise<TImpl>>;
@@ -164,17 +158,23 @@ export function createServiceFactory<
TScope extends 'root' | 'plugin',
TImpl extends TService,
TDeps extends { [name in string]: ServiceRef<unknown> },
TOpts extends MaybeOptions = undefined,
TOpts extends [options?: object] = [],
>(
config: ServiceFactoryConfig<TService, TScope, TImpl, TDeps, TOpts>,
): FactoryFunctionWithOptions<ServiceFactory<TService>, TOpts> {
return (options?: TOpts) =>
config:
| ServiceFactoryConfig<TService, TScope, TImpl, TDeps>
| ((
...options: TOpts
) => ServiceFactoryConfig<TService, TScope, TImpl, TDeps>),
): (...params: TOpts) => ServiceFactory<TService> {
if (typeof config === 'function') {
return (...opts: TOpts) => {
const c = config(...opts);
return { ...c, scope: c.service.scope } as ServiceFactory<TService>;
};
}
return () =>
({
...config,
scope: config.service.scope,
service: config.service,
deps: config.deps,
factory(deps: ServiceRefsToInstances<TDeps, 'root'>) {
return config.factory(deps, options!);
},
} as ServiceFactory<TService>);
}
-32
View File
@@ -1,32 +0,0 @@
/*
* 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.
*/
/**
* Base type for options objects that aren't required.
*
* @ignore
*/
export type MaybeOptions = object | undefined;
/**
* Helper type that makes the options argument optional if options are not required.
*
* @ignore
*/
export type FactoryFunctionWithOptions<TResult, TOptions> =
undefined extends TOptions
? (options?: TOptions) => TResult
: (options: TOptions) => TResult;
@@ -32,10 +32,10 @@ describe('createExtensionPoint', () => {
describe('createBackendPlugin', () => {
it('should create a BackendPlugin', () => {
const plugin = createBackendPlugin({
const plugin = createBackendPlugin((_options: { a: string }) => ({
id: 'x',
register(_reg, _options: { a: string }) {},
});
register() {},
}));
expect(plugin).toBeDefined();
expect(plugin({ a: 'a' })).toBeDefined();
expect(plugin({ a: 'a' }).id).toBe('x');
@@ -46,10 +46,10 @@ describe('createBackendPlugin', () => {
});
it('should create plugins with optional options', () => {
const plugin = createBackendPlugin({
const plugin = createBackendPlugin((_options?: { a: string }) => ({
id: 'x',
register(_reg, _options?: { a: string }) {},
});
register() {},
}));
expect(plugin).toBeDefined();
expect(plugin({ a: 'a' })).toBeDefined();
expect(plugin()).toBeDefined();
@@ -73,10 +73,10 @@ describe('createBackendPlugin', () => {
interface TestOptions {
a: string;
}
const plugin = createBackendPlugin({
const plugin = createBackendPlugin((_options: TestOptions) => ({
id: 'x',
register(_reg, _options: TestOptions) {},
});
register() {},
}));
expect(plugin).toBeDefined();
expect(plugin({ a: 'a' })).toBeDefined();
expect(plugin({ a: 'a' }).id).toBe('x');
@@ -90,10 +90,10 @@ describe('createBackendPlugin', () => {
interface TestOptions {
a: string;
}
const plugin = createBackendPlugin({
const plugin = createBackendPlugin((_options?: TestOptions) => ({
id: 'x',
register(_reg, _options?: TestOptions) {},
});
register() {},
}));
expect(plugin).toBeDefined();
expect(plugin({ a: 'a' })).toBeDefined();
expect(plugin()).toBeDefined();
@@ -104,11 +104,11 @@ describe('createBackendPlugin', () => {
describe('createBackendModule', () => {
it('should create a BackendModule', () => {
const mod = createBackendModule({
const mod = createBackendModule((_options: { a: string }) => ({
pluginId: 'x',
moduleId: 'y',
register(_reg, _options: { a: string }) {},
});
register() {},
}));
expect(mod).toBeDefined();
expect(mod({ a: 'a' })).toBeDefined();
expect(mod({ a: 'a' }).id).toBe('x.y');
@@ -119,11 +119,11 @@ describe('createBackendModule', () => {
});
it('should create modules with optional options', () => {
const mod = createBackendModule({
const mod = createBackendModule((_options?: { a: string }) => ({
pluginId: 'x',
moduleId: 'y',
register(_reg, _options?: { a: string }) {},
});
register() {},
}));
expect(mod).toBeDefined();
expect(mod({ a: 'a' })).toBeDefined();
expect(mod()).toBeDefined();
@@ -148,11 +148,11 @@ describe('createBackendModule', () => {
interface TestOptions {
a: string;
}
const mod = createBackendModule({
const mod = createBackendModule((_options: TestOptions) => ({
pluginId: 'x',
moduleId: 'y',
register(_reg, _options: TestOptions) {},
});
register() {},
}));
expect(mod).toBeDefined();
expect(mod({ a: 'a' })).toBeDefined();
expect(mod({ a: 'a' }).id).toBe('x.y');
@@ -166,11 +166,11 @@ describe('createBackendModule', () => {
interface TestOptions {
a: string;
}
const mod = createBackendModule({
const mod = createBackendModule((_options?: TestOptions) => ({
pluginId: 'x',
moduleId: 'y',
register(_reg, _options?: TestOptions) {},
});
register() {},
}));
expect(mod).toBeDefined();
expect(mod({ a: 'a' })).toBeDefined();
expect(mod()).toBeDefined();
@@ -14,7 +14,6 @@
* limitations under the License.
*/
import { FactoryFunctionWithOptions, MaybeOptions } from '../types';
import {
BackendRegistrationPoints,
BackendFeature,
@@ -43,30 +42,28 @@ export function createExtensionPoint<T>(
}
/** @public */
export interface BackendPluginConfig<TOptions> {
export interface BackendPluginConfig {
id: string;
register(reg: BackendRegistrationPoints, options: TOptions): void;
register(reg: BackendRegistrationPoints): void;
}
/** @public */
export function createBackendPlugin<TOptions extends MaybeOptions = undefined>(
config: BackendPluginConfig<TOptions>,
): FactoryFunctionWithOptions<BackendFeature, TOptions> {
return (options?: TOptions) => ({
id: config.id,
register(register: BackendRegistrationPoints) {
return config.register(register, options!);
},
});
export function createBackendPlugin<TOptions extends [options?: object] = []>(
config: BackendPluginConfig | ((...params: TOptions) => BackendPluginConfig),
): (...params: TOptions) => BackendFeature {
if (typeof config === 'function') {
return config;
}
return () => config;
}
/** @public */
export interface BackendModuleConfig<TOptions> {
export interface BackendModuleConfig {
pluginId: string;
moduleId: string;
register(
reg: Omit<BackendRegistrationPoints, 'registerExtensionPoint'>,
options: TOptions,
): void;
}
@@ -84,14 +81,23 @@ export interface BackendModuleConfig<TOptions> {
*
* The `pluginId` should exactly match the `id` of the plugin that the module extends.
*/
export function createBackendModule<TOptions extends MaybeOptions = undefined>(
config: BackendModuleConfig<TOptions>,
): FactoryFunctionWithOptions<BackendFeature, TOptions> {
return (options?: TOptions) => ({
export function createBackendModule<TOptions extends [options?: object] = []>(
config: BackendModuleConfig | ((...params: TOptions) => BackendModuleConfig),
): (...params: TOptions) => BackendFeature {
if (typeof config === 'function') {
return (...options: TOptions) => {
const c = config(...options);
return {
id: `${c.pluginId}.${c.moduleId}`,
register: c.register,
};
};
}
return () => ({
id: `${config.pluginId}.${config.moduleId}`,
register(register: BackendRegistrationPoints) {
// TODO: Hide registerExtensionPoint
return config.register(register, options!);
return config.register(register);
},
});
}
@@ -22,10 +22,12 @@ import { ConfigReader } from '@backstage/config';
import { JsonObject } from '@backstage/types';
/** @public */
export const mockConfigFactory = createServiceFactory({
service: coreServices.config,
deps: {},
async factory(_, options?: { data?: JsonObject }) {
return new ConfigReader(options?.data, 'mock-config');
},
});
export const mockConfigFactory = createServiceFactory(
(options?: { data?: JsonObject }) => ({
service: coreServices.config,
deps: {},
async factory() {
return new ConfigReader(options?.data, 'mock-config');
},
}),
);
+3 -3
View File
@@ -70,9 +70,9 @@ export type AppPluginOptions = {
* The App plugin is responsible for serving the frontend app bundle and static assets.
* @alpha
*/
export const appPlugin = createBackendPlugin({
export const appPlugin = createBackendPlugin((options: AppPluginOptions) => ({
id: 'app',
register(env, options: AppPluginOptions) {
register(env) {
env.registerInit({
deps: {
logger: coreServices.logger,
@@ -101,4 +101,4 @@ export const appPlugin = createBackendPlugin({
},
});
},
});
}));
@@ -90,7 +90,5 @@ export class AwsS3EntityProvider implements EntityProvider {
}
// @alpha
export const awsS3EntityProviderCatalogModule: (
options?: undefined,
) => BackendFeature;
export const awsS3EntityProviderCatalogModule: () => BackendFeature;
```
@@ -58,7 +58,5 @@ export class AzureDevOpsEntityProvider implements EntityProvider {
}
// @alpha
export const azureDevOpsEntityProviderCatalogModule: (
options?: undefined,
) => BackendFeature;
export const azureDevOpsEntityProviderCatalogModule: () => BackendFeature;
```
@@ -48,7 +48,5 @@ export class BitbucketCloudEntityProvider
}
// @alpha (undocumented)
export const bitbucketCloudEntityProviderCatalogModule: (
options?: undefined,
) => BackendFeature;
export const bitbucketCloudEntityProviderCatalogModule: () => BackendFeature;
```
@@ -69,9 +69,7 @@ export class BitbucketServerEntityProvider implements EntityProvider {
}
// @alpha (undocumented)
export const bitbucketServerEntityProviderCatalogModule: (
options?: undefined,
) => BackendFeature;
export const bitbucketServerEntityProviderCatalogModule: () => BackendFeature;
// @public (undocumented)
export type BitbucketServerListOptions = {
@@ -31,9 +31,7 @@ export class GerritEntityProvider implements EntityProvider {
}
// @alpha (undocumented)
export const gerritEntityProviderCatalogModule: (
options?: undefined,
) => BackendFeature;
export const gerritEntityProviderCatalogModule: () => BackendFeature;
// (No @packageDocumentation comment for this package)
```
@@ -101,9 +101,7 @@ export class GithubEntityProvider implements EntityProvider, EventSubscriber {
}
// @alpha
export const githubEntityProviderCatalogModule: (
options?: undefined,
) => BackendFeature;
export const githubEntityProviderCatalogModule: () => BackendFeature;
// @public (undocumented)
export class GithubLocationAnalyzer implements ScmLocationAnalyzer {
@@ -34,9 +34,7 @@ export class GitlabDiscoveryEntityProvider implements EntityProvider {
}
// @alpha
export const gitlabDiscoveryEntityProviderCatalogModule: (
options?: undefined,
) => BackendFeature;
export const gitlabDiscoveryEntityProviderCatalogModule: () => BackendFeature;
// @public
export class GitLabDiscoveryProcessor implements CatalogProcessor {
@@ -31,51 +31,50 @@ import { WrapperProviders } from './WrapperProviders';
* @alpha
*/
export const incrementalIngestionEntityProviderCatalogModule =
createBackendModule({
pluginId: 'catalog',
moduleId: 'incrementalIngestionEntityProvider',
register(
env,
options: {
providers: Array<{
provider: IncrementalEntityProvider<unknown, unknown>;
options: IncrementalEntityProviderOptions;
}>;
},
) {
env.registerInit({
deps: {
catalog: catalogProcessingExtensionPoint,
config: coreServices.config,
database: coreServices.database,
httpRouter: coreServices.httpRouter,
logger: coreServices.logger,
scheduler: coreServices.scheduler,
},
async init({
catalog,
config,
database,
httpRouter,
logger,
scheduler,
}) {
const client = await database.getClient();
const providers = new WrapperProviders({
createBackendModule(
(options: {
providers: Array<{
provider: IncrementalEntityProvider<unknown, unknown>;
options: IncrementalEntityProviderOptions;
}>;
}) => ({
pluginId: 'catalog',
moduleId: 'incrementalIngestionEntityProvider',
register(env) {
env.registerInit({
deps: {
catalog: catalogProcessingExtensionPoint,
config: coreServices.config,
database: coreServices.database,
httpRouter: coreServices.httpRouter,
logger: coreServices.logger,
scheduler: coreServices.scheduler,
},
async init({
catalog,
config,
database,
httpRouter,
logger,
client,
scheduler,
});
}) {
const client = await database.getClient();
for (const entry of options.providers) {
const wrapped = providers.wrap(entry.provider, entry.options);
catalog.addEntityProvider(wrapped);
}
const providers = new WrapperProviders({
config,
logger,
client,
scheduler,
});
httpRouter.use(await providers.adminRouter());
},
});
},
});
for (const entry of options.providers) {
const wrapped = providers.wrap(entry.provider, entry.options);
catalog.addEntityProvider(wrapped);
}
httpRouter.use(await providers.adminRouter());
},
});
},
}),
);
@@ -135,9 +135,7 @@ export class MicrosoftGraphOrgEntityProvider implements EntityProvider {
}
// @alpha
export const microsoftGraphOrgEntityProviderCatalogModule: (
options?: MicrosoftGraphOrgEntityProviderCatalogModuleOptions | undefined,
) => BackendFeature;
export const microsoftGraphOrgEntityProviderCatalogModule: () => BackendFeature;
// @alpha
export interface MicrosoftGraphOrgEntityProviderCatalogModuleOptions {
+1 -1
View File
@@ -237,7 +237,7 @@ export type CatalogPermissionRule<
> = PermissionRule<Entity, EntitiesSearchFilter, 'catalog-entity', TParams>;
// @alpha
export const catalogPlugin: (options?: undefined) => BackendFeature;
export const catalogPlugin: () => BackendFeature;
// @public
export interface CatalogProcessingEngine {
@@ -23,7 +23,5 @@ export class AwsSqsConsumingEventPublisher implements EventPublisher {
}
// @alpha
export const awsSqsConsumingEventPublisherEventsModule: (
options?: undefined,
) => BackendFeature;
export const awsSqsConsumingEventPublisherEventsModule: () => BackendFeature;
```
@@ -15,7 +15,5 @@ export class AzureDevOpsEventRouter extends SubTopicEventRouter {
}
// @alpha
export const azureDevOpsEventRouterEventsModule: (
options?: undefined,
) => BackendFeature;
export const azureDevOpsEventRouterEventsModule: () => BackendFeature;
```
@@ -15,7 +15,5 @@ export class BitbucketCloudEventRouter extends SubTopicEventRouter {
}
// @alpha
export const bitbucketCloudEventRouterEventsModule: (
options?: undefined,
) => BackendFeature;
export const bitbucketCloudEventRouterEventsModule: () => BackendFeature;
```
@@ -15,7 +15,5 @@ export class GerritEventRouter extends SubTopicEventRouter {
}
// @alpha
export const gerritEventRouterEventsModule: (
options?: undefined,
) => BackendFeature;
export const gerritEventRouterEventsModule: () => BackendFeature;
```
@@ -22,10 +22,8 @@ export class GithubEventRouter extends SubTopicEventRouter {
}
// @alpha
export const githubEventRouterEventsModule: (
options?: undefined,
) => BackendFeature;
export const githubEventRouterEventsModule: () => BackendFeature;
// @alpha
export const githubWebhookEventsModule: (options?: undefined) => BackendFeature;
export const githubWebhookEventsModule: () => BackendFeature;
```
@@ -20,10 +20,8 @@ export class GitlabEventRouter extends SubTopicEventRouter {
}
// @alpha
export const gitlabEventRouterEventsModule: (
options?: undefined,
) => BackendFeature;
export const gitlabEventRouterEventsModule: () => BackendFeature;
// @alpha
export const gitlabWebhookEventsModule: (options?: undefined) => BackendFeature;
export const gitlabWebhookEventsModule: () => BackendFeature;
```
+1 -1
View File
@@ -29,7 +29,7 @@ export class EventsBackend {
}
// @alpha
export const eventsPlugin: (options?: undefined) => BackendFeature;
export const eventsPlugin: () => BackendFeature;
// @public
export class HttpPostIngressEventPublisher implements EventPublisher {
+1 -1
View File
@@ -625,7 +625,7 @@ export type RunCommandOptions = {
};
// @alpha
export const scaffolderCatalogModule: (options?: undefined) => BackendFeature;
export const scaffolderCatalogModule: () => BackendFeature;
// @public (undocumented)
export class ScaffolderEntitiesProcessor implements CatalogProcessor {
@@ -70,72 +70,74 @@ export const scaffolderActionsExtensionPoint =
* Catalog plugin
* @alpha
*/
export const scaffolderPlugin = createBackendPlugin({
id: 'scaffolder',
register(env, options: ScaffolderPluginOptions) {
const actionsExtensions = new ScaffolderActionsExtensionPointImpl();
env.registerExtensionPoint(
scaffolderActionsExtensionPoint,
actionsExtensions,
);
export const scaffolderPlugin = createBackendPlugin(
(options: ScaffolderPluginOptions) => ({
id: 'scaffolder',
register(env) {
const actionsExtensions = new ScaffolderActionsExtensionPointImpl();
env.registerExtensionPoint(
scaffolderActionsExtensionPoint,
actionsExtensions,
);
env.registerInit({
deps: {
logger: coreServices.logger,
config: coreServices.config,
reader: coreServices.urlReader,
permissions: coreServices.permissions,
database: coreServices.database,
httpRouter: coreServices.httpRouter,
catalogClient: catalogServiceRef,
},
async init({
logger,
config,
reader,
database,
httpRouter,
catalogClient,
}) {
const {
additionalTemplateFilters,
taskBroker,
taskWorkers,
additionalTemplateGlobals,
} = options;
const log = loggerToWinstonLogger(logger);
env.registerInit({
deps: {
logger: coreServices.logger,
config: coreServices.config,
reader: coreServices.urlReader,
permissions: coreServices.permissions,
database: coreServices.database,
httpRouter: coreServices.httpRouter,
catalogClient: catalogServiceRef,
},
async init({
logger,
config,
reader,
database,
httpRouter,
catalogClient,
}) {
const {
additionalTemplateFilters,
taskBroker,
taskWorkers,
additionalTemplateGlobals,
} = options;
const log = loggerToWinstonLogger(logger);
const actions = options.actions || [
...actionsExtensions.actions,
...createBuiltinActions({
integrations: ScmIntegrations.fromConfig(config),
const actions = options.actions || [
...actionsExtensions.actions,
...createBuiltinActions({
integrations: ScmIntegrations.fromConfig(config),
catalogClient,
reader,
config,
additionalTemplateFilters,
additionalTemplateGlobals,
}),
];
const actionIds = actions.map(action => action.id).join(', ');
log.info(
`Starting scaffolder with the following actions enabled ${actionIds}`,
);
const router = await createRouter({
logger: log,
config,
database,
catalogClient,
reader,
config,
actions,
taskBroker,
taskWorkers,
additionalTemplateFilters,
additionalTemplateGlobals,
}),
];
const actionIds = actions.map(action => action.id).join(', ');
log.info(
`Starting scaffolder with the following actions enabled ${actionIds}`,
);
const router = await createRouter({
logger: log,
config,
database,
catalogClient,
reader,
actions,
taskBroker,
taskWorkers,
additionalTemplateFilters,
additionalTemplateGlobals,
});
httpRouter.use(router);
},
});
},
});
});
httpRouter.use(router);
},
});
},
}),
);