From d175692fd7a0e80d7e8e5582216ca51d14672dd7 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Thu, 10 Aug 2023 23:36:43 +0200 Subject: [PATCH 01/22] backend-plugin-api: make ServiceFactory backend feature Signed-off-by: Vincenzo Scamporlino --- .../src/services/system/index.ts | 1 + .../src/services/system/types.ts | 22 ++++++++++++++----- .../src/wiring/factories.ts | 6 +++-- .../backend-plugin-api/src/wiring/index.ts | 1 - .../backend-plugin-api/src/wiring/types.ts | 14 +----------- 5 files changed, 23 insertions(+), 21 deletions(-) diff --git a/packages/backend-plugin-api/src/services/system/index.ts b/packages/backend-plugin-api/src/services/system/index.ts index 2b91758cbc..7ffa5859c8 100644 --- a/packages/backend-plugin-api/src/services/system/index.ts +++ b/packages/backend-plugin-api/src/services/system/index.ts @@ -15,6 +15,7 @@ */ export type { + BackendFeature, ServiceRef, ServiceRefConfig, ServiceFactory, diff --git a/packages/backend-plugin-api/src/services/system/types.ts b/packages/backend-plugin-api/src/services/system/types.ts index 9465d4a9cb..ad8f28b565 100644 --- a/packages/backend-plugin-api/src/services/system/types.ts +++ b/packages/backend-plugin-api/src/services/system/types.ts @@ -51,9 +51,7 @@ export type ServiceRef< export interface ServiceFactory< TService = unknown, TScope extends 'plugin' | 'root' = 'plugin' | 'root', -> { - $$type: '@backstage/ServiceFactory'; - +> extends BackendFeature { service: ServiceRef; } @@ -87,6 +85,20 @@ export interface ServiceRefConfig { ) => Promise; } +/** @internal */ +export interface BackendFeatureFactory< + TOptions extends [options?: object] = [], +> { + (...options: TOptions): BackendFeature; + $$type: '@backstage/BackendFeatureFactory'; +} + +/** @public */ +export interface BackendFeature { + // NOTE: This type is opaque in order to simplify future API evolution. + $$type: '@backstage/BackendFeature'; +} + /** * Creates a new service definition. This overload is used to create plugin scoped services. * @@ -248,7 +260,7 @@ export function createServiceFactory< if (anyConf.service.scope === 'root') { const c = anyConf as RootServiceFactoryConfig; return { - $$type: '@backstage/ServiceFactory', + $$type: '@backstage/BackendFeature', version: 'v1', service: c.service, deps: c.deps, @@ -262,7 +274,7 @@ export function createServiceFactory< TDeps >; return { - $$type: '@backstage/ServiceFactory', + $$type: '@backstage/BackendFeature', version: 'v1', service: c.service, ...('createRootContext' in c diff --git a/packages/backend-plugin-api/src/wiring/factories.ts b/packages/backend-plugin-api/src/wiring/factories.ts index af40256411..646398e56c 100644 --- a/packages/backend-plugin-api/src/wiring/factories.ts +++ b/packages/backend-plugin-api/src/wiring/factories.ts @@ -14,14 +14,16 @@ * limitations under the License. */ +import { + BackendFeature, + BackendFeatureFactory, +} from '../services/system/types'; import { BackendModuleRegistrationPoints, BackendPluginRegistrationPoints, ExtensionPoint, InternalBackendModuleRegistration, InternalBackendPluginRegistration, - BackendFeatureFactory, - BackendFeature, } from './types'; /** diff --git a/packages/backend-plugin-api/src/wiring/index.ts b/packages/backend-plugin-api/src/wiring/index.ts index 9cb767b8ac..49f15c0b55 100644 --- a/packages/backend-plugin-api/src/wiring/index.ts +++ b/packages/backend-plugin-api/src/wiring/index.ts @@ -27,6 +27,5 @@ export { export type { BackendModuleRegistrationPoints, BackendPluginRegistrationPoints, - BackendFeature, ExtensionPoint, } from './types'; diff --git a/packages/backend-plugin-api/src/wiring/types.ts b/packages/backend-plugin-api/src/wiring/types.ts index d416ce7f9a..8b831b3a37 100644 --- a/packages/backend-plugin-api/src/wiring/types.ts +++ b/packages/backend-plugin-api/src/wiring/types.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { ServiceRef } from '../services/system/types'; +import { BackendFeature, ServiceRef } from '../services/system/types'; /** * TODO @@ -71,18 +71,6 @@ export interface BackendModuleRegistrationPoints { }): void; } -/** @internal */ -export interface BackendFeatureFactory { - (): BackendFeature; - $$type: '@backstage/BackendFeatureFactory'; -} - -/** @public */ -export interface BackendFeature { - // NOTE: This type is opaque in order to simplify future API evolution. - $$type: '@backstage/BackendFeature'; -} - /** @internal */ export interface InternalBackendFeature extends BackendFeature { version: 'v1'; From 966e3760568a78244cde48d8f6511ec1f4e5bf5c Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Thu, 10 Aug 2023 23:41:24 +0200 Subject: [PATCH 02/22] backend-app-api: rename services option to defaultServiceFactories Signed-off-by: Vincenzo Scamporlino --- .../src/wiring/createSpecializedBackend.test.ts | 8 +++++--- .../src/wiring/createSpecializedBackend.ts | 2 +- packages/backend-app-api/src/wiring/types.ts | 2 +- .../backend-test-utils/src/next/wiring/TestBackend.ts | 6 +++++- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/backend-app-api/src/wiring/createSpecializedBackend.test.ts b/packages/backend-app-api/src/wiring/createSpecializedBackend.test.ts index dc9a0cc085..1fd7fcbbec 100644 --- a/packages/backend-app-api/src/wiring/createSpecializedBackend.test.ts +++ b/packages/backend-app-api/src/wiring/createSpecializedBackend.test.ts @@ -22,13 +22,15 @@ import { createSpecializedBackend } from './createSpecializedBackend'; describe('createSpecializedBackend', () => { it('should create a backend without services', () => { - expect(() => createSpecializedBackend({ services: [] })).not.toThrow(); + expect(() => + createSpecializedBackend({ defaultServiceFactories: [] }), + ).not.toThrow(); }); it('should throw on duplicate service implementations', () => { expect(() => createSpecializedBackend({ - services: [ + defaultServiceFactories: [ createServiceFactory({ service: coreServices.rootLifecycle, deps: {}, @@ -55,7 +57,7 @@ describe('createSpecializedBackend', () => { it('should throw when providing a plugin metadata service implementation', () => { expect(() => createSpecializedBackend({ - services: [ + defaultServiceFactories: [ createServiceFactory({ service: coreServices.pluginMetadata, deps: {}, diff --git a/packages/backend-app-api/src/wiring/createSpecializedBackend.ts b/packages/backend-app-api/src/wiring/createSpecializedBackend.ts index 15e51f7c4c..f5c4d8b152 100644 --- a/packages/backend-app-api/src/wiring/createSpecializedBackend.ts +++ b/packages/backend-app-api/src/wiring/createSpecializedBackend.ts @@ -24,7 +24,7 @@ import { Backend, CreateSpecializedBackendOptions } from './types'; export function createSpecializedBackend( options: CreateSpecializedBackendOptions, ): Backend { - const services = options.services.map(sf => + const services = options.defaultServiceFactories.map(sf => typeof sf === 'function' ? sf() : sf, ); diff --git a/packages/backend-app-api/src/wiring/types.ts b/packages/backend-app-api/src/wiring/types.ts index ffedb40324..36e2dede30 100644 --- a/packages/backend-app-api/src/wiring/types.ts +++ b/packages/backend-app-api/src/wiring/types.ts @@ -34,7 +34,7 @@ export interface Backend { * @public */ export interface CreateSpecializedBackendOptions { - services: ServiceFactoryOrFunction[]; + defaultServiceFactories: ServiceFactoryOrFunction[]; } export interface ServiceHolder { diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.ts index 06e27e5c07..0bade8bfbb 100644 --- a/packages/backend-test-utils/src/next/wiring/TestBackend.ts +++ b/packages/backend-test-utils/src/next/wiring/TestBackend.ts @@ -279,7 +279,11 @@ export async function startTestBackend< const backend = createSpecializedBackend({ ...otherOptions, - services: [...factories, rootHttpRouterFactory, discoveryFactory], + defaultServiceFactories: [ + ...factories, + rootHttpRouterFactory, + discoveryFactory, + ], }); backendInstancesToCleanUp.push(backend); From 108728f5fea1e33bf1a2380ddaa7a6353d4ee9ef Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Thu, 10 Aug 2023 23:57:32 +0200 Subject: [PATCH 03/22] backend-app-api: add add method to ServiceRegistry Signed-off-by: Vincenzo Scamporlino --- packages/backend-app-api/src/wiring/ServiceRegistry.ts | 9 ++++++++- packages/backend-app-api/src/wiring/types.ts | 2 ++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/backend-app-api/src/wiring/ServiceRegistry.ts b/packages/backend-app-api/src/wiring/ServiceRegistry.ts index 61f95ff4a4..25d777549c 100644 --- a/packages/backend-app-api/src/wiring/ServiceRegistry.ts +++ b/packages/backend-app-api/src/wiring/ServiceRegistry.ts @@ -39,7 +39,7 @@ function toInternalServiceFactory( factory: ServiceFactory, ): InternalServiceFactory { const f = factory as InternalServiceFactory; - if (f.$$type !== '@backstage/ServiceFactory') { + if (f.$$type !== '@backstage/BackendFeature') { throw new Error(`Invalid service factory, bad type '${f.$$type}'`); } if (f.version !== 'v1') { @@ -82,6 +82,13 @@ export class ServiceRegistry implements EnumerableServiceHolder { this.#implementations = new Map(); } + add(serviceFactory: ServiceFactory) { + this.#providedFactories.set( + serviceFactory.service.id, + toInternalServiceFactory(serviceFactory), + ); + } + #resolveFactory( ref: ServiceRef, pluginId: string, diff --git a/packages/backend-app-api/src/wiring/types.ts b/packages/backend-app-api/src/wiring/types.ts index 36e2dede30..e2cc299541 100644 --- a/packages/backend-app-api/src/wiring/types.ts +++ b/packages/backend-app-api/src/wiring/types.ts @@ -19,6 +19,7 @@ import { ExtensionPoint, ServiceRef, ServiceFactoryOrFunction, + ServiceFactory, } from '@backstage/backend-plugin-api'; /** @@ -39,6 +40,7 @@ export interface CreateSpecializedBackendOptions { export interface ServiceHolder { get(api: ServiceRef, pluginId: string): Promise | undefined; + add(serviceFactory: ServiceFactory): void; } /** From 90fdcfb403342871f8a448274af7088dc41f40e7 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Thu, 10 Aug 2023 23:58:44 +0200 Subject: [PATCH 04/22] backend-app-api: add methods accepts a backend feature factory Signed-off-by: Vincenzo Scamporlino --- packages/backend-app-api/src/wiring/BackstageBackend.ts | 4 ++-- packages/backend-app-api/src/wiring/types.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/backend-app-api/src/wiring/BackstageBackend.ts b/packages/backend-app-api/src/wiring/BackstageBackend.ts index c53f47b685..beeefc1b1b 100644 --- a/packages/backend-app-api/src/wiring/BackstageBackend.ts +++ b/packages/backend-app-api/src/wiring/BackstageBackend.ts @@ -28,8 +28,8 @@ export class BackstageBackend implements Backend { this.#initializer = new BackendInitializer(this.#services); } - add(feature: BackendFeature): void { - this.#initializer.add(feature); + add(feature: BackendFeature | (() => BackendFeature)): void { + this.#initializer.add(typeof feature === 'function' ? feature() : feature); } async start(): Promise { diff --git a/packages/backend-app-api/src/wiring/types.ts b/packages/backend-app-api/src/wiring/types.ts index e2cc299541..0a43caae59 100644 --- a/packages/backend-app-api/src/wiring/types.ts +++ b/packages/backend-app-api/src/wiring/types.ts @@ -26,7 +26,7 @@ import { * @public */ export interface Backend { - add(feature: BackendFeature): void; + add(feature: BackendFeature | (() => BackendFeature)): void; start(): Promise; stop(): Promise; } From 7af5f7320f87475a6cc0581105657c295e2516bf Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 11 Aug 2023 00:00:06 +0200 Subject: [PATCH 05/22] backend-defaults: remove options from createBackend Signed-off-by: Vincenzo Scamporlino --- .../src/CreateBackend.test.ts | 89 ++++++++++--------- .../backend-defaults/src/CreateBackend.ts | 29 +----- packages/backend-defaults/src/index.ts | 1 - 3 files changed, 48 insertions(+), 71 deletions(-) diff --git a/packages/backend-defaults/src/CreateBackend.test.ts b/packages/backend-defaults/src/CreateBackend.test.ts index de04d4e350..0b36b57069 100644 --- a/packages/backend-defaults/src/CreateBackend.test.ts +++ b/packages/backend-defaults/src/CreateBackend.test.ts @@ -22,60 +22,63 @@ import { createBackend } from './CreateBackend'; describe('createBackend', () => { it('should not throw when overriding a default service implementation', () => { - expect(() => - createBackend({ - services: [ - createServiceFactory({ - service: coreServices.rootLifecycle, - deps: {}, - factory: async () => ({ - addStartupHook: () => {}, - addShutdownHook: () => {}, - }), + const backend = createBackend(); + + expect(() => { + backend.add( + createServiceFactory({ + service: coreServices.rootLifecycle, + deps: {}, + factory: async () => ({ + addStartupHook: () => {}, + addShutdownHook: () => {}, }), - ], - }), - ).not.toThrow(); + }), + ); + }).not.toThrow(); }); it('should throw on duplicate service implementations', () => { - expect(() => - createBackend({ - services: [ - createServiceFactory({ - service: coreServices.rootLifecycle, - deps: {}, - factory: async () => ({ - addStartupHook: () => {}, - addShutdownHook: () => {}, - }), - }), - createServiceFactory({ - service: coreServices.rootLifecycle, - deps: {}, - factory: async () => ({ - addStartupHook: () => {}, - addShutdownHook: () => {}, - }), - }), - ], + const backend = createBackend(); + + backend.add( + createServiceFactory({ + service: coreServices.rootLifecycle, + deps: {}, + factory: async () => ({ + addStartupHook: () => {}, + addShutdownHook: () => {}, + }), }), - ).toThrow( + ); + + expect(() => { + backend.add( + createServiceFactory({ + service: coreServices.rootLifecycle, + deps: {}, + factory: async () => ({ + addStartupHook: () => {}, + addShutdownHook: () => {}, + }), + }), + ); + }).toThrow( 'Duplicate service implementations provided for core.rootLifecycle', ); }); it('should throw when providing a plugin metadata service implementation', () => { + const backend = createBackend(); + expect(() => - createBackend({ - services: [ - createServiceFactory({ - service: coreServices.pluginMetadata, - deps: {}, - factory: async () => ({ getId: () => 'test' }), - }), - ], - }), + backend.add( + createServiceFactory({ + service: coreServices.pluginMetadata, + deps: {}, + factory: async () => ({ getId: () => 'test' }), + }), + ), ).toThrow('The core.pluginMetadata service cannot be overridden'); }); }); diff --git a/packages/backend-defaults/src/CreateBackend.ts b/packages/backend-defaults/src/CreateBackend.ts index 3db013a290..c07d1cc38a 100644 --- a/packages/backend-defaults/src/CreateBackend.ts +++ b/packages/backend-defaults/src/CreateBackend.ts @@ -33,10 +33,6 @@ import { urlReaderServiceFactory, identityServiceFactory, } from '@backstage/backend-app-api'; -import { - ServiceFactory, - ServiceFactoryOrFunction, -} from '@backstage/backend-plugin-api'; export const defaultServiceFactories = [ cacheServiceFactory(), @@ -59,27 +55,6 @@ export const defaultServiceFactories = [ /** * @public */ -export interface CreateBackendOptions { - services?: ServiceFactoryOrFunction[]; -} - -/** - * @public - */ -export function createBackend(options?: CreateBackendOptions): Backend { - const services = new Array(); - - // Highest priority: Services passed directly to createBackend - const providedServices = (options?.services ?? []).map(sf => - typeof sf === 'function' ? sf() : sf, - ); - services.push(...providedServices); - - // Lowest priority: Default services that are not already provided by environment or directly to createBackend - const defaultServices = defaultServiceFactories.filter( - sf => !services.some(({ service }) => service.id === sf.service.id), - ); - services.push(...defaultServices); - - return createSpecializedBackend({ services }); +export function createBackend(): Backend { + return createSpecializedBackend({ defaultServiceFactories }); } diff --git a/packages/backend-defaults/src/index.ts b/packages/backend-defaults/src/index.ts index 833878744e..d3e36cf0fb 100644 --- a/packages/backend-defaults/src/index.ts +++ b/packages/backend-defaults/src/index.ts @@ -25,5 +25,4 @@ // TODO(Rugvip): Remove this once backend-common is no longer used by backend-app-api import '@backstage/backend-common'; -export type { CreateBackendOptions } from './CreateBackend'; export { createBackend } from './CreateBackend'; From b10bf736d0609bca5022cebc0865ae4ecfce02f4 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 11 Aug 2023 00:07:33 +0200 Subject: [PATCH 06/22] backend-app-api: accepts service factory as feature Signed-off-by: Vincenzo Scamporlino --- .../src/wiring/BackendInitializer.ts | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/packages/backend-app-api/src/wiring/BackendInitializer.ts b/packages/backend-app-api/src/wiring/BackendInitializer.ts index f71256d04e..ab4a059aac 100644 --- a/packages/backend-app-api/src/wiring/BackendInitializer.ts +++ b/packages/backend-app-api/src/wiring/BackendInitializer.ts @@ -19,6 +19,7 @@ import { ExtensionPoint, coreServices, ServiceRef, + ServiceFactory, } from '@backstage/backend-plugin-api'; import { BackendLifecycleImpl } from '../services/implementations/rootLifecycle/rootLifecycleServiceFactory'; import { BackendPluginLifecycleImpl } from '../services/implementations/lifecycle/lifecycleServiceFactory'; @@ -104,13 +105,21 @@ export class BackendInitializer { `Failed to add feature, invalid type '${feature.$$type}'`, ); } - const internalFeature = feature as InternalBackendFeature; - if (internalFeature.version !== 'v1') { + + if (isServiceFactory(feature)) { + this.#serviceHolder.add(feature); + } else if (isInternalBackendFeature(feature)) { + if (feature.version !== 'v1') { + throw new Error( + `Failed to add feature, invalid version '${feature.version}'`, + ); + } + this.#features.push(feature); + } else { throw new Error( - `Failed to add feature, invalid version '${internalFeature.version}'`, + `Failed to add feature, invalid feature ${JSON.stringify(feature)}`, ); } - this.#features.push(internalFeature); } async start(): Promise { @@ -342,3 +351,15 @@ export class BackendInitializer { throw new Error('Unexpected plugin lifecycle service implementation'); } } + +function isServiceFactory(feature: BackendFeature): feature is ServiceFactory { + return !!(feature as ServiceFactory).service; +} + +function isInternalBackendFeature( + feature: BackendFeature, +): feature is InternalBackendFeature { + return ( + typeof (feature as InternalBackendFeature).getRegistrations === 'function' + ); +} From d1546d5c5bf9c0e267342aa73479b1b95fc8f59c Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 11 Aug 2023 00:08:54 +0200 Subject: [PATCH 07/22] catalog-backend-module-incremental-ingestion: adapt to new createBackend api Signed-off-by: Vincenzo Scamporlino --- .../src/run.ts | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/plugins/catalog-backend-module-incremental-ingestion/src/run.ts b/plugins/catalog-backend-module-incremental-ingestion/src/run.ts index be1a6dcfc0..e99ec7e41a 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/src/run.ts +++ b/plugins/catalog-backend-module-incremental-ingestion/src/run.ts @@ -55,16 +55,15 @@ async function main() { }, }; - const backend = createBackend({ - services: [ - createServiceFactory({ - service: coreServices.rootConfig, - deps: {}, - factory: () => new ConfigReader(config), - }), - ], - }); + const backend = createBackend(); + backend.add( + createServiceFactory({ + service: coreServices.rootConfig, + deps: {}, + factory: () => new ConfigReader(config), + }), + ); backend.add(catalogPlugin()); backend.add(catalogModuleIncrementalIngestionEntityProvider()); backend.add( From a6d7983f349c37ce0ae16e4f45c5a6eb4be42dd3 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 11 Aug 2023 00:18:53 +0200 Subject: [PATCH 08/22] createBackend changeset Signed-off-by: Vincenzo Scamporlino --- .changeset/young-lies-attack.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .changeset/young-lies-attack.md diff --git a/.changeset/young-lies-attack.md b/.changeset/young-lies-attack.md new file mode 100644 index 0000000000..0e9fc21e22 --- /dev/null +++ b/.changeset/young-lies-attack.md @@ -0,0 +1,21 @@ +--- +'@backstage/backend-plugin-api': patch +'@backstage/backend-test-utils': patch +'@backstage/backend-defaults': patch +'@backstage/backend-app-api': patch +--- + +Removed options from `createBackend`. + +The `createBackend` method doesn't accept any options anymore as in the following: + +```ts +const backend = createBackend({ services: [myCustomServiceFactory] }); +``` + +In order to pass custom service factories use the `add` method: + +```ts +const backend = createBackend(); +backend.add(customRootLoggerServiceFactory); +``` From 95799fba222d8665c9df62ea4c1d2060c8d6c9c0 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 11 Aug 2023 00:22:35 +0200 Subject: [PATCH 09/22] catalog-backend-module-incremental-ingestion backend feature changeset Signed-off-by: Vincenzo Scamporlino --- .changeset/selfish-pumas-draw.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/selfish-pumas-draw.md diff --git a/.changeset/selfish-pumas-draw.md b/.changeset/selfish-pumas-draw.md new file mode 100644 index 0000000000..9893b896ba --- /dev/null +++ b/.changeset/selfish-pumas-draw.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-incremental-ingestion': patch +--- + +Use new backend feature api to customize `rootConfig`. From 0c1f57b6b6d047363e38449f49a8b53c455058cd Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Fri, 11 Aug 2023 08:47:09 +0200 Subject: [PATCH 10/22] backend-app-api: add missing check for pluginMetadata service Signed-off-by: Vincenzo Scamporlino --- packages/backend-app-api/src/wiring/BackendInitializer.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/backend-app-api/src/wiring/BackendInitializer.ts b/packages/backend-app-api/src/wiring/BackendInitializer.ts index ab4a059aac..2e90e6eb2c 100644 --- a/packages/backend-app-api/src/wiring/BackendInitializer.ts +++ b/packages/backend-app-api/src/wiring/BackendInitializer.ts @@ -107,6 +107,11 @@ export class BackendInitializer { } if (isServiceFactory(feature)) { + if (feature.service.id === coreServices.pluginMetadata.id) { + throw new Error( + `The ${coreServices.pluginMetadata.id} service cannot be overridden`, + ); + } this.#serviceHolder.add(feature); } else if (isInternalBackendFeature(feature)) { if (feature.version !== 'v1') { From 263f6be4f6221f0c834e8c0a176c017319d5f502 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Tue, 15 Aug 2023 00:08:19 +0200 Subject: [PATCH 11/22] backend-app-api: keep ServiceRegistry immutable Signed-off-by: Vincenzo Scamporlino --- packages/backend-app-api/src/wiring/ServiceRegistry.ts | 7 ------- packages/backend-app-api/src/wiring/types.ts | 2 -- 2 files changed, 9 deletions(-) diff --git a/packages/backend-app-api/src/wiring/ServiceRegistry.ts b/packages/backend-app-api/src/wiring/ServiceRegistry.ts index 25d777549c..b6de05b361 100644 --- a/packages/backend-app-api/src/wiring/ServiceRegistry.ts +++ b/packages/backend-app-api/src/wiring/ServiceRegistry.ts @@ -82,13 +82,6 @@ export class ServiceRegistry implements EnumerableServiceHolder { this.#implementations = new Map(); } - add(serviceFactory: ServiceFactory) { - this.#providedFactories.set( - serviceFactory.service.id, - toInternalServiceFactory(serviceFactory), - ); - } - #resolveFactory( ref: ServiceRef, pluginId: string, diff --git a/packages/backend-app-api/src/wiring/types.ts b/packages/backend-app-api/src/wiring/types.ts index 0a43caae59..552a69a792 100644 --- a/packages/backend-app-api/src/wiring/types.ts +++ b/packages/backend-app-api/src/wiring/types.ts @@ -19,7 +19,6 @@ import { ExtensionPoint, ServiceRef, ServiceFactoryOrFunction, - ServiceFactory, } from '@backstage/backend-plugin-api'; /** @@ -40,7 +39,6 @@ export interface CreateSpecializedBackendOptions { export interface ServiceHolder { get(api: ServiceRef, pluginId: string): Promise | undefined; - add(serviceFactory: ServiceFactory): void; } /** From 6e7a1b07f3986cb9a68267077c170ecd36e428c3 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Tue, 15 Aug 2023 00:10:21 +0200 Subject: [PATCH 12/22] backend-app-api: keep track of the provided services Signed-off-by: Vincenzo Scamporlino --- .../src/wiring/BackendInitializer.test.ts | 38 +++++++++---------- .../src/wiring/BackendInitializer.ts | 28 ++++++++++---- .../src/wiring/BackstageBackend.ts | 9 ++--- 3 files changed, 42 insertions(+), 33 deletions(-) diff --git a/packages/backend-app-api/src/wiring/BackendInitializer.test.ts b/packages/backend-app-api/src/wiring/BackendInitializer.test.ts index b90bcf6691..791b9b1c3a 100644 --- a/packages/backend-app-api/src/wiring/BackendInitializer.test.ts +++ b/packages/backend-app-api/src/wiring/BackendInitializer.test.ts @@ -23,7 +23,7 @@ import { createExtensionPoint, } from '@backstage/backend-plugin-api'; import { BackendInitializer } from './BackendInitializer'; -import { ServiceRegistry } from './ServiceRegistry'; + import { lifecycleServiceFactory, loggerServiceFactory, @@ -65,7 +65,7 @@ describe('BackendInitializer', () => { const rootFactory = jest.fn(); const pluginFactory = jest.fn(); - const registry = new ServiceRegistry([ + const services = [ createServiceFactory({ service: rootRef, deps: {}, @@ -82,9 +82,9 @@ describe('BackendInitializer', () => { deps: {}, factory: () => new MockLogger(), })(), - ]); + ]; - const init = new BackendInitializer(registry); + const init = new BackendInitializer(services); await init.start(); expect(rootFactory).toHaveBeenCalled(); @@ -97,7 +97,7 @@ describe('BackendInitializer', () => { const extensionPoint = createExtensionPoint<{ values: string[] }>({ id: 'a', }); - const init = new BackendInitializer(new ServiceRegistry(baseFactories)); + const init = new BackendInitializer(baseFactories); init.add( createBackendModule({ @@ -151,7 +151,7 @@ describe('BackendInitializer', () => { }); it('should forward errors when plugins fail to start', async () => { - const init = new BackendInitializer(new ServiceRegistry([])); + const init = new BackendInitializer([]); init.add( createBackendPlugin({ pluginId: 'test', @@ -171,7 +171,7 @@ describe('BackendInitializer', () => { }); it('should forward errors when modules fail to start', async () => { - const init = new BackendInitializer(new ServiceRegistry([])); + const init = new BackendInitializer([]); init.add( createBackendModule({ pluginId: 'test', @@ -192,7 +192,7 @@ describe('BackendInitializer', () => { }); it('should reject duplicate plugins', async () => { - const init = new BackendInitializer(new ServiceRegistry([])); + const init = new BackendInitializer([]); init.add( createBackendPlugin({ pluginId: 'test', @@ -221,7 +221,7 @@ describe('BackendInitializer', () => { }); it('should reject duplicate modules', async () => { - const init = new BackendInitializer(new ServiceRegistry([])); + const init = new BackendInitializer([]); init.add( createBackendModule({ pluginId: 'test', @@ -254,16 +254,14 @@ describe('BackendInitializer', () => { it('should reject modules with circular dependencies', async () => { const extA = createExtensionPoint({ id: 'a' }); const extB = createExtensionPoint({ id: 'b' }); - const init = new BackendInitializer( - new ServiceRegistry([ - rootLifecycleServiceFactory(), - createServiceFactory({ - service: coreServices.rootLogger, - deps: {}, - factory: () => new MockLogger(), - })(), - ]), - ); + const init = new BackendInitializer([ + rootLifecycleServiceFactory(), + createServiceFactory({ + service: coreServices.rootLogger, + deps: {}, + factory: () => new MockLogger(), + })(), + ]); init.add( createBackendModule({ pluginId: 'test', @@ -296,7 +294,7 @@ describe('BackendInitializer', () => { }); it('should reject modules that depend on extension points other plugins', async () => { - const init = new BackendInitializer(new ServiceRegistry(baseFactories)); + const init = new BackendInitializer(baseFactories); const extA = createExtensionPoint({ id: 'a' }); init.add( createBackendPlugin({ diff --git a/packages/backend-app-api/src/wiring/BackendInitializer.ts b/packages/backend-app-api/src/wiring/BackendInitializer.ts index 2e90e6eb2c..b6f79e19da 100644 --- a/packages/backend-app-api/src/wiring/BackendInitializer.ts +++ b/packages/backend-app-api/src/wiring/BackendInitializer.ts @@ -30,6 +30,7 @@ import { InternalBackendFeature } from '@backstage/backend-plugin-api/src/wiring import { ForwardedError, ConflictError } from '@backstage/errors'; import { featureDiscoveryServiceRef } from '@backstage/backend-plugin-api/alpha'; import { DependencyGraph } from '../lib/DependencyGraph'; +import { ServiceRegistry } from './ServiceRegistry'; export interface BackendRegisterInit { consumes: Set; @@ -47,10 +48,12 @@ export class BackendInitializer { ExtensionPoint, { impl: unknown; pluginId: string } >(); - #serviceHolder: EnumerableServiceHolder; + #serviceHolder: EnumerableServiceHolder | undefined; + #providedServiceFactories = new Array(); + #defaultApiFactories: ServiceFactory[]; - constructor(serviceHolder: EnumerableServiceHolder) { - this.#serviceHolder = serviceHolder; + constructor(defaultApiFactories: ServiceFactory[]) { + this.#defaultApiFactories = defaultApiFactories; } async #getInitDeps( @@ -70,7 +73,7 @@ export class BackendInitializer { } result.set(name, ep.impl); } else { - const impl = await this.#serviceHolder.get( + const impl = await this.#serviceHolder!.get( ref as ServiceRef, pluginId, ); @@ -112,7 +115,16 @@ export class BackendInitializer { `The ${coreServices.pluginMetadata.id} service cannot be overridden`, ); } - this.#serviceHolder.add(feature); + if ( + this.#providedServiceFactories.find( + sf => sf.service.id === feature.service.id, + ) + ) { + throw new Error( + `Duplicate service implementations provided for ${feature.service.id}`, + ); + } + this.#providedServiceFactories.push(feature); } else if (isInternalBackendFeature(feature)) { if (feature.version !== 'v1') { throw new Error( @@ -155,6 +167,8 @@ export class BackendInitializer { } async #doStart(): Promise { + this.#serviceHolder = new ServiceRegistry(this.#defaultApiFactories); + const featureDiscovery = await this.#serviceHolder.get( featureDiscoveryServiceRef, 'root', @@ -333,7 +347,7 @@ export class BackendInitializer { // Bit of a hacky way to grab the lifecycle services, potentially find a nicer way to do this async #getRootLifecycleImpl(): Promise { - const lifecycleService = await this.#serviceHolder.get( + const lifecycleService = await this.#serviceHolder!.get( coreServices.rootLifecycle, 'root', ); @@ -346,7 +360,7 @@ export class BackendInitializer { async #getPluginLifecycleImpl( pluginId: string, ): Promise { - const lifecycleService = await this.#serviceHolder.get( + const lifecycleService = await this.#serviceHolder!.get( coreServices.lifecycle, pluginId, ); diff --git a/packages/backend-app-api/src/wiring/BackstageBackend.ts b/packages/backend-app-api/src/wiring/BackstageBackend.ts index beeefc1b1b..0ea55bc1c7 100644 --- a/packages/backend-app-api/src/wiring/BackstageBackend.ts +++ b/packages/backend-app-api/src/wiring/BackstageBackend.ts @@ -14,18 +14,15 @@ * limitations under the License. */ -import { ServiceFactory, BackendFeature } from '@backstage/backend-plugin-api'; +import { BackendFeature, ServiceFactory } from '@backstage/backend-plugin-api'; import { BackendInitializer } from './BackendInitializer'; -import { ServiceRegistry } from './ServiceRegistry'; import { Backend } from './types'; export class BackstageBackend implements Backend { - #services: ServiceRegistry; #initializer: BackendInitializer; - constructor(apiFactories: ServiceFactory[]) { - this.#services = new ServiceRegistry(apiFactories); - this.#initializer = new BackendInitializer(this.#services); + constructor(defaultServiceFactories: ServiceFactory[]) { + this.#initializer = new BackendInitializer(defaultServiceFactories); } add(feature: BackendFeature | (() => BackendFeature)): void { From f5f81edb6b3099ae787a51c03171be75532cfbbe Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Tue, 15 Aug 2023 00:35:32 +0200 Subject: [PATCH 13/22] Update .changeset/young-lies-attack.md Co-authored-by: Patrik Oldsberg Signed-off-by: Vincenzo Scamporlino --- .changeset/young-lies-attack.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.changeset/young-lies-attack.md b/.changeset/young-lies-attack.md index 0e9fc21e22..24c74a6503 100644 --- a/.changeset/young-lies-attack.md +++ b/.changeset/young-lies-attack.md @@ -5,9 +5,7 @@ '@backstage/backend-app-api': patch --- -Removed options from `createBackend`. - -The `createBackend` method doesn't accept any options anymore as in the following: +**BREAKING**: Removed options from `createBackend`. Service factories are now `BackendFeature`s and should be installed with `backend.add(...)` instead. The following should be migrated: ```ts const backend = createBackend({ services: [myCustomServiceFactory] }); From fa9028b68070ee7a79c4e741f765a99f569a0ed8 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Tue, 15 Aug 2023 00:36:24 +0200 Subject: [PATCH 14/22] Apply suggestions from code review Co-authored-by: Patrik Oldsberg Signed-off-by: Vincenzo Scamporlino --- .changeset/young-lies-attack.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/young-lies-attack.md b/.changeset/young-lies-attack.md index 24c74a6503..ebf6401d17 100644 --- a/.changeset/young-lies-attack.md +++ b/.changeset/young-lies-attack.md @@ -11,7 +11,7 @@ const backend = createBackend({ services: [myCustomServiceFactory] }); ``` -In order to pass custom service factories use the `add` method: +To instead pass the service factory via `backend.add(...)`: ```ts const backend = createBackend(); From c37c19cc3768d5c2531f514618431339b2af3bfe Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Tue, 15 Aug 2023 00:57:22 +0200 Subject: [PATCH 15/22] backend-plugin-api: move BackendFactory to common types Signed-off-by: Vincenzo Scamporlino --- packages/backend-plugin-api/src/index.ts | 1 + .../src/services/system/index.ts | 1 - .../src/services/system/types.ts | 16 ++-------- packages/backend-plugin-api/src/types.ts | 29 +++++++++++++++++++ .../src/wiring/factories.ts | 5 +--- .../backend-plugin-api/src/wiring/types.ts | 3 +- 6 files changed, 35 insertions(+), 20 deletions(-) create mode 100644 packages/backend-plugin-api/src/types.ts diff --git a/packages/backend-plugin-api/src/index.ts b/packages/backend-plugin-api/src/index.ts index 452fa046f9..8e0b23d20b 100644 --- a/packages/backend-plugin-api/src/index.ts +++ b/packages/backend-plugin-api/src/index.ts @@ -21,4 +21,5 @@ */ export * from './services'; +export type { BackendFeature } from './types'; export * from './wiring'; diff --git a/packages/backend-plugin-api/src/services/system/index.ts b/packages/backend-plugin-api/src/services/system/index.ts index 7ffa5859c8..2b91758cbc 100644 --- a/packages/backend-plugin-api/src/services/system/index.ts +++ b/packages/backend-plugin-api/src/services/system/index.ts @@ -15,7 +15,6 @@ */ export type { - BackendFeature, ServiceRef, ServiceRefConfig, ServiceFactory, diff --git a/packages/backend-plugin-api/src/services/system/types.ts b/packages/backend-plugin-api/src/services/system/types.ts index ad8f28b565..bea53dc1ed 100644 --- a/packages/backend-plugin-api/src/services/system/types.ts +++ b/packages/backend-plugin-api/src/services/system/types.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { BackendFeature } from '../../types'; + /** * TODO * @@ -85,20 +87,6 @@ export interface ServiceRefConfig { ) => Promise; } -/** @internal */ -export interface BackendFeatureFactory< - TOptions extends [options?: object] = [], -> { - (...options: TOptions): BackendFeature; - $$type: '@backstage/BackendFeatureFactory'; -} - -/** @public */ -export interface BackendFeature { - // NOTE: This type is opaque in order to simplify future API evolution. - $$type: '@backstage/BackendFeature'; -} - /** * Creates a new service definition. This overload is used to create plugin scoped services. * diff --git a/packages/backend-plugin-api/src/types.ts b/packages/backend-plugin-api/src/types.ts new file mode 100644 index 0000000000..59f1106fab --- /dev/null +++ b/packages/backend-plugin-api/src/types.ts @@ -0,0 +1,29 @@ +/* + * 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. + */ + +/** @internal */ +export interface BackendFeatureFactory< + TOptions extends [options?: object] = [], +> { + (...options: TOptions): BackendFeature; + $$type: '@backstage/BackendFeatureFactory'; +} + +/** @public */ +export interface BackendFeature { + // NOTE: This type is opaque in order to simplify future API evolution. + $$type: '@backstage/BackendFeature'; +} diff --git a/packages/backend-plugin-api/src/wiring/factories.ts b/packages/backend-plugin-api/src/wiring/factories.ts index 646398e56c..9fa0f87bab 100644 --- a/packages/backend-plugin-api/src/wiring/factories.ts +++ b/packages/backend-plugin-api/src/wiring/factories.ts @@ -14,10 +14,7 @@ * limitations under the License. */ -import { - BackendFeature, - BackendFeatureFactory, -} from '../services/system/types'; +import { BackendFeature, BackendFeatureFactory } from '../types'; import { BackendModuleRegistrationPoints, BackendPluginRegistrationPoints, diff --git a/packages/backend-plugin-api/src/wiring/types.ts b/packages/backend-plugin-api/src/wiring/types.ts index 8b831b3a37..55d43ccb7c 100644 --- a/packages/backend-plugin-api/src/wiring/types.ts +++ b/packages/backend-plugin-api/src/wiring/types.ts @@ -14,7 +14,8 @@ * limitations under the License. */ -import { BackendFeature, ServiceRef } from '../services/system/types'; +import { ServiceRef } from '../services/system/types'; +import { BackendFeature } from '../types'; /** * TODO From 175e4c3516d7dc1b4738652216059e9af5e40fd3 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Tue, 15 Aug 2023 01:08:17 +0200 Subject: [PATCH 16/22] api-reports Signed-off-by: Vincenzo Scamporlino --- packages/backend-app-api/api-report.md | 4 ++-- packages/backend-defaults/api-report.md | 9 +-------- packages/backend-plugin-api/api-report.md | 4 +--- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/packages/backend-app-api/api-report.md b/packages/backend-app-api/api-report.md index 675a7755fc..0fa1ff376e 100644 --- a/packages/backend-app-api/api-report.md +++ b/packages/backend-app-api/api-report.md @@ -43,7 +43,7 @@ import { UrlReader } from '@backstage/backend-common'; // @public (undocumented) export interface Backend { // (undocumented) - add(feature: BackendFeature): void; + add(feature: BackendFeature | (() => BackendFeature)): void; // (undocumented) start(): Promise; // (undocumented) @@ -81,7 +81,7 @@ export function createSpecializedBackend( // @public (undocumented) export interface CreateSpecializedBackendOptions { // (undocumented) - services: ServiceFactoryOrFunction[]; + defaultServiceFactories: ServiceFactoryOrFunction[]; } // @public (undocumented) diff --git a/packages/backend-defaults/api-report.md b/packages/backend-defaults/api-report.md index 6cc58de663..ab9cc5775c 100644 --- a/packages/backend-defaults/api-report.md +++ b/packages/backend-defaults/api-report.md @@ -4,14 +4,7 @@ ```ts import { Backend } from '@backstage/backend-app-api'; -import { ServiceFactoryOrFunction } from '@backstage/backend-plugin-api'; // @public (undocumented) -export function createBackend(options?: CreateBackendOptions): Backend; - -// @public (undocumented) -export interface CreateBackendOptions { - // (undocumented) - services?: ServiceFactoryOrFunction[]; -} +export function createBackend(): Backend; ``` diff --git a/packages/backend-plugin-api/api-report.md b/packages/backend-plugin-api/api-report.md index 0789168926..17cc521499 100644 --- a/packages/backend-plugin-api/api-report.md +++ b/packages/backend-plugin-api/api-report.md @@ -409,9 +409,7 @@ export type SearchResponseFile = { export interface ServiceFactory< TService = unknown, TScope extends 'plugin' | 'root' = 'plugin' | 'root', -> { - // (undocumented) - $$type: '@backstage/ServiceFactory'; +> extends BackendFeature { // (undocumented) service: ServiceRef; } From f66d4903326ce3f4440cad82c1779a2ae152a5f5 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Tue, 15 Aug 2023 14:34:15 +0200 Subject: [PATCH 17/22] backend-test-utils: remove services from startTestBackend Signed-off-by: Vincenzo Scamporlino --- .../featureDiscoveryServiceFactory.test.ts | 2 +- .../scheduler/schedulerServiceFactory.test.ts | 3 +- .../src/wiring/ServiceRegistry.test.ts | 22 +++--- packages/backend-test-utils/api-report.md | 24 +----- .../src/next/wiring/TestBackend.test.ts | 54 ++++++++----- .../src/next/wiring/TestBackend.ts | 76 ++++--------------- .../app-backend/src/service/appPlugin.test.ts | 4 +- .../catalogModuleAwsS3EntityProvider.test.ts | 30 +++++--- ...logModuleAzureDevOpsEntityProvider.test.ts | 27 ++++--- ...ModuleBitbucketCloudEntityProvider.test.ts | 15 +++- ...oduleBitbucketServerEntityProvider.test.ts | 27 ++++--- .../catalogModuleGerritEntityProvider.test.ts | 27 ++++--- .../catalogModuleGithubEntityProvider.test.ts | 26 ++++--- ...oduleGitlabDiscoveryEntityProvider.test.ts | 27 ++++--- ...IncrementalIngestionEntityProvider.test.ts | 31 ++------ .../src/run.ts | 2 +- ...uleMicrosoftGraphOrgEntityProvider.test.ts | 26 ++++--- ...atalogModulePuppetDbEntityProvider.test.ts | 26 ++++--- .../performance/stitchingPerformance.test.ts | 4 +- ...oduleAwsSqsConsumingEventPublisher.test.ts | 75 +++++++++--------- ...eventsModuleAzureDevOpsEventRouter.test.ts | 1 - ...ntsModuleBitbucketCloudEventRouter.test.ts | 1 - .../eventsModuleGerritEventRouter.test.ts | 1 - .../eventsModuleGithubEventRouter.test.ts | 1 - .../service/eventsModuleGithubWebhook.test.ts | 30 ++++---- .../eventsModuleGitlabEventRouter.test.ts | 1 - .../service/eventsModuleGitlabWebhook.test.ts | 30 ++++---- .../src/service/EventsPlugin.test.ts | 37 +++++---- .../src/alpha.test.ts | 4 +- .../src/alpha.test.ts | 4 +- .../src/alpha.test.ts | 4 +- 31 files changed, 317 insertions(+), 325 deletions(-) diff --git a/packages/backend-app-api/src/alpha/featureDiscoveryServiceFactory.test.ts b/packages/backend-app-api/src/alpha/featureDiscoveryServiceFactory.test.ts index 5a5917dd3b..5d4b1fc551 100644 --- a/packages/backend-app-api/src/alpha/featureDiscoveryServiceFactory.test.ts +++ b/packages/backend-app-api/src/alpha/featureDiscoveryServiceFactory.test.ts @@ -95,7 +95,7 @@ describe('featureDiscoveryServiceFactory', () => { const fn = jest.fn().mockResolvedValue({}); await startTestBackend({ - services: [ + features: [ createServiceFactory({ service: coreServices.identity, deps: {}, diff --git a/packages/backend-app-api/src/services/implementations/scheduler/schedulerServiceFactory.test.ts b/packages/backend-app-api/src/services/implementations/scheduler/schedulerServiceFactory.test.ts index 7af9de44da..d771c5dd11 100644 --- a/packages/backend-app-api/src/services/implementations/scheduler/schedulerServiceFactory.test.ts +++ b/packages/backend-app-api/src/services/implementations/scheduler/schedulerServiceFactory.test.ts @@ -61,8 +61,7 @@ describe('schedulerFactory', () => { }); await startTestBackend({ - features: [plugin()], - services: [subject], + features: [plugin(), subject], }); }); }); diff --git a/packages/backend-app-api/src/wiring/ServiceRegistry.test.ts b/packages/backend-app-api/src/wiring/ServiceRegistry.test.ts index e698ade348..b60a24c8d8 100644 --- a/packages/backend-app-api/src/wiring/ServiceRegistry.test.ts +++ b/packages/backend-app-api/src/wiring/ServiceRegistry.test.ts @@ -31,7 +31,7 @@ const sf1 = createServiceFactory({ async factory() { return { x: 1 }; }, -})(); +}); const ref2 = createServiceRef<{ x: number }>({ scope: 'root', @@ -43,14 +43,14 @@ const sf2 = createServiceFactory({ async factory() { return { x: 2 }; }, -})(); +}); const sf2b = createServiceFactory({ service: ref2, deps: {}, async factory() { return { x: 22 }; }, -})(); +}); const refDefault1 = createServiceRef<{ x: number }>({ id: '1', @@ -61,7 +61,7 @@ const refDefault1 = createServiceRef<{ x: number }>({ async factory() { return { x: 10 }; }, - })(), + }), }); const refDefault2a = createServiceRef<{ x: number }>({ @@ -95,7 +95,7 @@ describe('ServiceRegistry', () => { }); it('should return an implementation for a registered ref', async () => { - const registry = new ServiceRegistry([sf1]); + const registry = new ServiceRegistry([sf1()]); await expect(registry.get(ref1, 'catalog')).resolves.toEqual({ x: 1 }); await expect(registry.get(ref1, 'scaffolder')).resolves.toEqual({ x: 1 }); expect(await registry.get(ref1, 'catalog')).toBe( @@ -110,7 +110,7 @@ describe('ServiceRegistry', () => { }); it('should handle multiple factories with different serviceRefs', async () => { - const registry = new ServiceRegistry([sf1, sf2]); + const registry = new ServiceRegistry([sf1(), sf2()]); await expect(registry.get(ref1, 'catalog')).resolves.toEqual({ x: 1, @@ -131,7 +131,7 @@ describe('ServiceRegistry', () => { return { x: 2 }; }, }); - const registry = new ServiceRegistry([factory(), sf1]); + const registry = new ServiceRegistry([factory(), sf1()]); await expect(registry.get(ref2, 'catalog')).rejects.toThrow( "Failed to instantiate 'root' scoped service '2' because it depends on 'plugin' scoped service '1'.", ); @@ -145,7 +145,7 @@ describe('ServiceRegistry', () => { return { x: rootDep.x }; }, }); - const registry = new ServiceRegistry([factory(), sf2]); + const registry = new ServiceRegistry([factory(), sf2()]); await expect(registry.get(ref1, 'catalog')).resolves.toEqual({ x: 2, }); @@ -160,7 +160,7 @@ describe('ServiceRegistry', () => { return { x: rootDep.x }; }, }); - const registry = new ServiceRegistry([factory(), sf2]); + const registry = new ServiceRegistry([factory(), sf2()]); await expect(registry.get(ref, 'catalog')).resolves.toEqual({ x: 2, }); @@ -182,7 +182,7 @@ describe('ServiceRegistry', () => { }); it('should use the last factory for each ref', async () => { - const registry = new ServiceRegistry([sf2, sf2b]); + const registry = new ServiceRegistry([sf2(), sf2b()]); await expect(registry.get(ref2, 'catalog')).resolves.toEqual({ x: 22, }); @@ -196,7 +196,7 @@ describe('ServiceRegistry', () => { }); it('should not use the defaultFactory from the ref if provided to the registry', async () => { - const registry = new ServiceRegistry([sf1]); + const registry = new ServiceRegistry([sf1()]); await expect(registry.get(refDefault1, 'catalog')).resolves.toEqual({ x: 1, }); diff --git a/packages/backend-test-utils/api-report.md b/packages/backend-test-utils/api-report.md index 1cb7a83a0e..d086b1d2ae 100644 --- a/packages/backend-test-utils/api-report.md +++ b/packages/backend-test-utils/api-report.md @@ -21,7 +21,6 @@ import { RootConfigService } from '@backstage/backend-plugin-api'; import { RootLifecycleService } from '@backstage/backend-plugin-api'; import { SchedulerService } from '@backstage/backend-plugin-api'; import { ServiceFactory } from '@backstage/backend-plugin-api'; -import { ServiceRef } from '@backstage/backend-plugin-api'; import { TokenManagerService } from '@backstage/backend-plugin-api'; import { UrlReaderService } from '@backstage/backend-plugin-api'; @@ -127,11 +126,8 @@ export function setupRequestMockHandlers(worker: { }): void; // @public (undocumented) -export function startTestBackend< - TServices extends any[], - TExtensionPoints extends any[], ->( - options: TestBackendOptions, +export function startTestBackend( + options: TestBackendOptions, ): Promise; // @public (undocumented) @@ -140,10 +136,7 @@ export interface TestBackend extends Backend { } // @public (undocumented) -export interface TestBackendOptions< - TServices extends any[], - TExtensionPoints extends any[], -> { +export interface TestBackendOptions { // (undocumented) extensionPoints?: readonly [ ...{ @@ -154,16 +147,7 @@ export interface TestBackendOptions< }, ]; // (undocumented) - features?: BackendFeature[]; - // (undocumented) - services?: readonly [ - ...{ - [index in keyof TServices]: - | ServiceFactory - | (() => ServiceFactory) - | [ServiceRef, Partial]; - }, - ]; + features?: Array BackendFeature)>; } // @public diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts index 13b57f54ba..b127712927 100644 --- a/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts +++ b/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts @@ -31,7 +31,6 @@ import { startTestBackend } from './TestBackend'; let globalTestBackendHasBeenStopped = false; beforeAll(async () => { await startTestBackend({ - services: [], features: [ createBackendModule({ moduleId: 'test.module', @@ -46,7 +45,7 @@ beforeAll(async () => { }, }); }, - })(), + }), ], }); }); @@ -68,17 +67,37 @@ describe('TestBackend', () => { const extensionPoint5 = createExtensionPoint({ id: 'b5' }); await expect( startTestBackend({ - services: [ + features: [ // @ts-expect-error [extensionPoint1, { a: 'a' }], - [serviceRef, { a: 'a' }], - [serviceRef, { a: 'a', b: 'b' }], - // @ts-expect-error - [serviceRef, { c: 'c' }], - // @ts-expect-error - [serviceRef, { a: 'a', c: 'c' }], - // @ts-expect-error - [serviceRef, { a: 'a', b: 'b', c: 'c' }], + createServiceFactory(() => ({ + service: serviceRef, + deps: {}, + // @ts-expect-error + factory: async () => ({ a: 'a' }), + })), + createServiceFactory(() => ({ + service: serviceRef, + deps: {}, + factory: async () => ({ a: 'a', b: 'b' }), + })), + createServiceFactory(() => ({ + service: serviceRef, + deps: {}, + // @ts-expect-error + factory: async () => ({ c: 'c' }), + })), + createServiceFactory(() => ({ + service: serviceRef, + deps: {}, + // @ts-expect-error + factory: async () => ({ a: 'a', c: 'c' }), + })), + createServiceFactory(() => ({ + service: serviceRef, + deps: {}, + factory: async () => ({ a: 'a', b: 'b', c: 'c' }), + })), ], extensionPoints: [ // @ts-expect-error @@ -124,8 +143,7 @@ describe('TestBackend', () => { }); await startTestBackend({ - services: [sf], - features: [testModule()], + features: [testModule(), sf()], }); expect(testFn).toHaveBeenCalledWith('winning'); @@ -150,7 +168,6 @@ describe('TestBackend', () => { }); const backend = await startTestBackend({ - services: [], features: [testModule()], }); @@ -192,7 +209,6 @@ describe('TestBackend', () => { }); await startTestBackend({ - services: [], features: [testPlugin()], }); }); @@ -244,7 +260,7 @@ describe('TestBackend', () => { }, }); }, - })(), + }), createBackendModule({ pluginId: 'testB', moduleId: 'test', @@ -256,7 +272,7 @@ describe('TestBackend', () => { }, }); }, - })(), + }), ], }), ).resolves.not.toBeUndefined(); @@ -277,7 +293,7 @@ describe('TestBackend', () => { async init() {}, }); }, - })(), + }), createBackendModule({ pluginId: 'testB', moduleId: 'test', @@ -287,7 +303,7 @@ describe('TestBackend', () => { async init() {}, }); }, - })(), + }), ], }), ).rejects.toThrow( diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.ts index 0bade8bfbb..13c05eb61c 100644 --- a/packages/backend-test-utils/src/next/wiring/TestBackend.ts +++ b/packages/backend-test-utils/src/next/wiring/TestBackend.ts @@ -24,8 +24,6 @@ import { } from '@backstage/backend-app-api'; import { HostDiscovery } from '@backstage/backend-common'; import { - ServiceFactory, - ServiceRef, createServiceFactory, BackendFeature, ExtensionPoint, @@ -40,18 +38,7 @@ import express from 'express'; import { InternalBackendFeature } from '@backstage/backend-plugin-api/src/wiring/types'; /** @public */ -export interface TestBackendOptions< - TServices extends any[], - TExtensionPoints extends any[], -> { - services?: readonly [ - ...{ - [index in keyof TServices]: - | ServiceFactory - | (() => ServiceFactory) - | [ServiceRef, Partial]; - }, - ]; +export interface TestBackendOptions { extensionPoints?: readonly [ ...{ [index in keyof TExtensionPoints]: [ @@ -60,7 +47,7 @@ export interface TestBackendOptions< ]; }, ]; - features?: BackendFeature[]; + features?: Array BackendFeature)>; } /** @public */ @@ -95,17 +82,22 @@ const defaultServiceFactories = [ * @returns */ function createExtensionPointTestModules( - features: BackendFeature[], + features: Array BackendFeature)>, extensionPointTuples?: readonly [ ref: ExtensionPoint, impl: unknown, ][], -): BackendFeature[] { +): Array<() => BackendFeature> { if (!extensionPointTuples) { return []; } - const registrations = features.flatMap(feature => { + const registrations = features.flatMap(featureOrFunction => { + const feature = + typeof featureOrFunction === 'function' + ? featureOrFunction() + : featureOrFunction; + if (feature.$$type !== '@backstage/BackendFeature') { throw new Error( `Failed to add feature, invalid type '${feature.$$type}'`, @@ -170,7 +162,7 @@ function createExtensionPointTestModules( reg.registerInit({ deps: {}, async init() {} }); }, - })(), + }), ); } @@ -180,18 +172,10 @@ function createExtensionPointTestModules( const backendInstancesToCleanUp = new Array(); /** @public */ -export async function startTestBackend< - TServices extends any[], - TExtensionPoints extends any[], ->( - options: TestBackendOptions, +export async function startTestBackend( + options: TestBackendOptions, ): Promise { - const { - services = [], - extensionPoints, - features = [], - ...otherOptions - } = options; + const { extensionPoints, features = [], ...otherOptions } = options; let server: ExtendedHttpServer; @@ -247,40 +231,10 @@ export async function startTestBackend< }, }); - const factories = services.map(serviceDef => { - if (Array.isArray(serviceDef)) { - // if type is ExtensionPoint? - // do something differently? - const [ref, impl] = serviceDef; - if (ref.scope === 'plugin') { - return createServiceFactory({ - service: ref as ServiceRef, - deps: {}, - factory: async () => impl, - })(); - } - return createServiceFactory({ - service: ref as ServiceRef, - deps: {}, - factory: async () => impl, - })(); - } - if (typeof serviceDef === 'function') { - return serviceDef(); - } - return serviceDef as ServiceFactory; - }); - - for (const factory of defaultServiceFactories) { - if (!factories.some(f => f.service.id === factory.service.id)) { - factories.push(factory); - } - } - const backend = createSpecializedBackend({ ...otherOptions, defaultServiceFactories: [ - ...factories, + ...defaultServiceFactories, rootHttpRouterFactory, discoveryFactory, ], diff --git a/plugins/app-backend/src/service/appPlugin.test.ts b/plugins/app-backend/src/service/appPlugin.test.ts index 37d38663ef..b6a972b4c7 100644 --- a/plugins/app-backend/src/service/appPlugin.test.ts +++ b/plugins/app-backend/src/service/appPlugin.test.ts @@ -39,8 +39,8 @@ describe('appPlugin', () => { it('boots', async () => { const { server } = await startTestBackend({ - features: [appPlugin()], - services: [ + features: [ + appPlugin(), mockServices.rootConfig.factory({ data: { app: { diff --git a/plugins/catalog-backend-module-aws/src/module/catalogModuleAwsS3EntityProvider.test.ts b/plugins/catalog-backend-module-aws/src/module/catalogModuleAwsS3EntityProvider.test.ts index 7599f8446f..c9fea8aa28 100644 --- a/plugins/catalog-backend-module-aws/src/module/catalogModuleAwsS3EntityProvider.test.ts +++ b/plugins/catalog-backend-module-aws/src/module/catalogModuleAwsS3EntityProvider.test.ts @@ -15,13 +15,15 @@ */ import { getVoidLogger } from '@backstage/backend-common'; -import { coreServices } from '@backstage/backend-plugin-api'; +import { + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; import { PluginTaskScheduler, TaskScheduleDefinition, } from '@backstage/backend-tasks'; -import { startTestBackend } from '@backstage/backend-test-utils'; -import { ConfigReader } from '@backstage/config'; +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { Duration } from 'luxon'; import { catalogModuleAwsS3EntityProvider } from './catalogModuleAwsS3EntityProvider'; @@ -45,7 +47,7 @@ describe('catalogModuleAwsS3EntityProvider', () => { }, } as unknown as PluginTaskScheduler; - const config = new ConfigReader({ + const config = { catalog: { providers: { awsS3: { @@ -57,16 +59,24 @@ describe('catalogModuleAwsS3EntityProvider', () => { }, }, }, - }); + }; await startTestBackend({ extensionPoints: [[catalogProcessingExtensionPoint, extensionPoint]], - services: [ - [coreServices.rootConfig, config], - [coreServices.logger, getVoidLogger()], - [coreServices.scheduler, scheduler], + features: [ + catalogModuleAwsS3EntityProvider(), + mockServices.rootConfig.factory({ data: config }), + createServiceFactory(() => ({ + service: coreServices.logger, + deps: {}, + factory: getVoidLogger, + }))(), + createServiceFactory(() => ({ + service: coreServices.scheduler, + deps: {}, + factory: () => scheduler, + }))(), ], - features: [catalogModuleAwsS3EntityProvider()], }); expect(usedSchedule?.frequency).toEqual(Duration.fromISO('P1M')); diff --git a/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.test.ts b/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.test.ts index e3140f4583..3147a0871b 100644 --- a/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.test.ts +++ b/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.test.ts @@ -14,14 +14,15 @@ * limitations under the License. */ -import { getVoidLogger } from '@backstage/backend-common'; -import { coreServices } from '@backstage/backend-plugin-api'; +import { + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; import { PluginTaskScheduler, TaskScheduleDefinition, } from '@backstage/backend-tasks'; -import { startTestBackend } from '@backstage/backend-test-utils'; -import { ConfigReader } from '@backstage/config'; +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { Duration } from 'luxon'; import { catalogModuleAzureDevOpsEntityProvider } from './catalogModuleAzureDevOpsEntityProvider'; @@ -45,7 +46,7 @@ describe('catalogModuleAzureDevOpsEntityProvider', () => { }, } as unknown as PluginTaskScheduler; - const config = new ConfigReader({ + const config = { catalog: { providers: { azureDevOps: { @@ -60,16 +61,20 @@ describe('catalogModuleAzureDevOpsEntityProvider', () => { }, }, }, - }); + }; await startTestBackend({ extensionPoints: [[catalogProcessingExtensionPoint, extensionPoint]], - services: [ - [coreServices.rootConfig, config], - [coreServices.logger, getVoidLogger()], - [coreServices.scheduler, scheduler], + features: [ + catalogModuleAzureDevOpsEntityProvider(), + mockServices.rootConfig.factory({ data: config }), + mockServices.logger.factory(), + createServiceFactory(() => ({ + deps: {}, + service: coreServices.scheduler, + factory: async () => scheduler, + })), ], - features: [catalogModuleAzureDevOpsEntityProvider()], }); expect(usedSchedule?.frequency).toEqual(Duration.fromISO('P1M')); diff --git a/plugins/catalog-backend-module-bitbucket-cloud/src/module/catalogModuleBitbucketCloudEntityProvider.test.ts b/plugins/catalog-backend-module-bitbucket-cloud/src/module/catalogModuleBitbucketCloudEntityProvider.test.ts index b46304d4e3..83769fc3f5 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/src/module/catalogModuleBitbucketCloudEntityProvider.test.ts +++ b/plugins/catalog-backend-module-bitbucket-cloud/src/module/catalogModuleBitbucketCloudEntityProvider.test.ts @@ -14,7 +14,10 @@ * limitations under the License. */ -import { coreServices } from '@backstage/backend-plugin-api'; +import { + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; import { PluginTaskScheduler, TaskScheduleDefinition, @@ -55,7 +58,8 @@ describe('catalogModuleBitbucketCloudEntityProvider', () => { [catalogProcessingExtensionPoint, catalogExtensionPointImpl], [eventsExtensionPoint, eventsExtensionPointImpl], ], - services: [ + features: [ + catalogModuleBitbucketCloudEntityProvider(), mockServices.rootConfig.factory({ data: { catalog: { @@ -71,9 +75,12 @@ describe('catalogModuleBitbucketCloudEntityProvider', () => { }, }, }), - [coreServices.scheduler, scheduler], + createServiceFactory({ + service: coreServices.scheduler, + deps: {}, + factory: async () => scheduler, + }), ], - features: [catalogModuleBitbucketCloudEntityProvider()], }); expect(usedSchedule?.frequency).toEqual(Duration.fromISO('P1M')); diff --git a/plugins/catalog-backend-module-bitbucket-server/src/module/catalogModuleBitbucketServerEntityProvider.test.ts b/plugins/catalog-backend-module-bitbucket-server/src/module/catalogModuleBitbucketServerEntityProvider.test.ts index f072823052..ae4a636008 100644 --- a/plugins/catalog-backend-module-bitbucket-server/src/module/catalogModuleBitbucketServerEntityProvider.test.ts +++ b/plugins/catalog-backend-module-bitbucket-server/src/module/catalogModuleBitbucketServerEntityProvider.test.ts @@ -14,14 +14,15 @@ * limitations under the License. */ -import { ConfigReader } from '@backstage/config'; -import { getVoidLogger } from '@backstage/backend-common'; -import { coreServices } from '@backstage/backend-plugin-api'; +import { + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; import { PluginTaskScheduler, TaskScheduleDefinition, } from '@backstage/backend-tasks'; -import { startTestBackend } from '@backstage/backend-test-utils'; +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { catalogModuleBitbucketServerEntityProvider } from './catalogModuleBitbucketServerEntityProvider'; import { Duration } from 'luxon'; @@ -45,7 +46,7 @@ describe('catalogModuleBitbucketServerEntityProvider', () => { }, } as unknown as PluginTaskScheduler; - const config = new ConfigReader({ + const config = { catalog: { providers: { bitbucketServer: { @@ -64,16 +65,20 @@ describe('catalogModuleBitbucketServerEntityProvider', () => { }, ], }, - }); + }; await startTestBackend({ extensionPoints: [[catalogProcessingExtensionPoint, extensionPoint]], - services: [ - [coreServices.rootConfig, config], - [coreServices.logger, getVoidLogger()], - [coreServices.scheduler, scheduler], + features: [ + catalogModuleBitbucketServerEntityProvider(), + mockServices.rootConfig.factory({ data: config }), + mockServices.logger.factory(), + createServiceFactory({ + service: coreServices.scheduler, + deps: {}, + factory: async () => scheduler, + }), ], - features: [catalogModuleBitbucketServerEntityProvider()], }); expect(usedSchedule?.frequency).toEqual(Duration.fromISO('P1M')); diff --git a/plugins/catalog-backend-module-gerrit/src/module/catalogModuleGerritEntityProvider.test.ts b/plugins/catalog-backend-module-gerrit/src/module/catalogModuleGerritEntityProvider.test.ts index 464837124f..9807814f61 100644 --- a/plugins/catalog-backend-module-gerrit/src/module/catalogModuleGerritEntityProvider.test.ts +++ b/plugins/catalog-backend-module-gerrit/src/module/catalogModuleGerritEntityProvider.test.ts @@ -14,14 +14,15 @@ * limitations under the License. */ -import { getVoidLogger } from '@backstage/backend-common'; -import { coreServices } from '@backstage/backend-plugin-api'; +import { + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; import { PluginTaskScheduler, TaskScheduleDefinition, } from '@backstage/backend-tasks'; -import { startTestBackend } from '@backstage/backend-test-utils'; -import { ConfigReader } from '@backstage/config'; +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { Duration } from 'luxon'; import { catalogModuleGerritEntityProvider } from './catalogModuleGerritEntityProvider'; @@ -45,7 +46,7 @@ describe('catalogModuleGerritEntityProvider', () => { }, } as unknown as PluginTaskScheduler; - const config = new ConfigReader({ + const config = { catalog: { providers: { gerrit: { @@ -70,16 +71,20 @@ describe('catalogModuleGerritEntityProvider', () => { }, ], }, - }); + }; await startTestBackend({ extensionPoints: [[catalogProcessingExtensionPoint, extensionPoint]], - services: [ - [coreServices.rootConfig, config], - [coreServices.logger, getVoidLogger()], - [coreServices.scheduler, scheduler], + features: [ + catalogModuleGerritEntityProvider(), + mockServices.rootConfig.factory({ data: config }), + mockServices.logger.factory(), + createServiceFactory({ + service: coreServices.scheduler, + deps: {}, + factory: async () => scheduler, + }), ], - features: [catalogModuleGerritEntityProvider()], }); expect(usedSchedule?.frequency).toEqual(Duration.fromISO('P1M')); diff --git a/plugins/catalog-backend-module-github/src/module/catalogModuleGithubEntityProvider.test.ts b/plugins/catalog-backend-module-github/src/module/catalogModuleGithubEntityProvider.test.ts index ca82e58e26..9e36966eec 100644 --- a/plugins/catalog-backend-module-github/src/module/catalogModuleGithubEntityProvider.test.ts +++ b/plugins/catalog-backend-module-github/src/module/catalogModuleGithubEntityProvider.test.ts @@ -14,18 +14,19 @@ * limitations under the License. */ -import { getVoidLogger } from '@backstage/backend-common'; -import { coreServices } from '@backstage/backend-plugin-api'; import { PluginTaskScheduler, TaskScheduleDefinition, } from '@backstage/backend-tasks'; -import { startTestBackend } from '@backstage/backend-test-utils'; -import { ConfigReader } from '@backstage/config'; +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { Duration } from 'luxon'; import { catalogModuleGithubEntityProvider } from './catalogModuleGithubEntityProvider'; import { GithubEntityProvider } from '../providers/GithubEntityProvider'; +import { + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; describe('catalogModuleGithubEntityProvider', () => { it('should register provider at the catalog extension point', async () => { @@ -45,7 +46,7 @@ describe('catalogModuleGithubEntityProvider', () => { }, } as unknown as PluginTaskScheduler; - const config = new ConfigReader({ + const config = { catalog: { providers: { github: { @@ -57,16 +58,19 @@ describe('catalogModuleGithubEntityProvider', () => { }, }, }, - }); + }; await startTestBackend({ extensionPoints: [[catalogProcessingExtensionPoint, extensionPoint]], - services: [ - [coreServices.rootConfig, config], - [coreServices.logger, getVoidLogger()], - [coreServices.scheduler, scheduler], + features: [ + catalogModuleGithubEntityProvider(), + mockServices.rootConfig.factory({ data: config }), + createServiceFactory({ + service: coreServices.scheduler, + deps: {}, + factory: async () => scheduler, + }), ], - features: [catalogModuleGithubEntityProvider()], }); expect(usedSchedule?.frequency).toEqual(Duration.fromISO('P1M')); diff --git a/plugins/catalog-backend-module-gitlab/src/module/catalogModuleGitlabDiscoveryEntityProvider.test.ts b/plugins/catalog-backend-module-gitlab/src/module/catalogModuleGitlabDiscoveryEntityProvider.test.ts index da11601f09..22759cafa0 100644 --- a/plugins/catalog-backend-module-gitlab/src/module/catalogModuleGitlabDiscoveryEntityProvider.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/module/catalogModuleGitlabDiscoveryEntityProvider.test.ts @@ -14,14 +14,15 @@ * limitations under the License. */ -import { getVoidLogger } from '@backstage/backend-common'; -import { coreServices } from '@backstage/backend-plugin-api'; +import { + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; import { PluginTaskScheduler, TaskScheduleDefinition, } from '@backstage/backend-tasks'; -import { startTestBackend } from '@backstage/backend-test-utils'; -import { ConfigReader } from '@backstage/config'; +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { Duration } from 'luxon'; import { catalogModuleGitlabDiscoveryEntityProvider } from './catalogModuleGitlabDiscoveryEntityProvider'; @@ -45,7 +46,7 @@ describe('catalogModuleGitlabDiscoveryEntityProvider', () => { }, } as unknown as PluginTaskScheduler; - const config = new ConfigReader({ + const config = { integrations: { gitlab: [ { @@ -69,16 +70,20 @@ describe('catalogModuleGitlabDiscoveryEntityProvider', () => { }, }, }, - }); + }; await startTestBackend({ extensionPoints: [[catalogProcessingExtensionPoint, extensionPoint]], - services: [ - [coreServices.rootConfig, config], - [coreServices.logger, getVoidLogger()], - [coreServices.scheduler, scheduler], + features: [ + catalogModuleGitlabDiscoveryEntityProvider(), + mockServices.rootConfig.factory({ data: config }), + mockServices.logger.factory(), + createServiceFactory({ + deps: {}, + service: coreServices.scheduler, + factory: async () => scheduler, + }), ], - features: [catalogModuleGitlabDiscoveryEntityProvider()], }); expect(usedSchedule?.frequency).toEqual(Duration.fromISO('P1M')); diff --git a/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.test.ts b/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.test.ts index 7c3dfdf226..ffb70a3060 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.test.ts +++ b/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.test.ts @@ -14,13 +14,8 @@ * limitations under the License. */ -import { getVoidLogger } from '@backstage/backend-common'; -import { - coreServices, - createBackendModule, -} from '@backstage/backend-plugin-api'; -import { startTestBackend } from '@backstage/backend-test-utils'; -import { ConfigReader } from '@backstage/config'; +import { createBackendModule } from '@backstage/backend-plugin-api'; +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { IncrementalEntityProvider } from '../types'; import { @@ -43,26 +38,16 @@ describe('catalogModuleIncrementalIngestionEntityProvider', () => { const addEntityProvider = jest.fn(); const httpRouterUse = jest.fn(); - const scheduler = {}; - const database = { - getClient: jest.fn(), - }; - const httpRouter = { - use: httpRouterUse, - }; - await startTestBackend({ extensionPoints: [ [catalogProcessingExtensionPoint, { addEntityProvider }], ], - services: [ - [coreServices.rootConfig, new ConfigReader({})], - [coreServices.database, database], - [coreServices.httpRouter, httpRouter], - [coreServices.logger, getVoidLogger()], - [coreServices.scheduler, scheduler], - ], features: [ + mockServices.rootConfig.factory(), + mockServices.database.factory(), + mockServices.httpRouter.factory(), + mockServices.logger.factory(), + mockServices.scheduler.factory(), catalogModuleIncrementalIngestionEntityProvider(), createBackendModule({ pluginId: 'catalog', @@ -82,7 +67,7 @@ describe('catalogModuleIncrementalIngestionEntityProvider', () => { }, }); }, - })(), + }), ], }); diff --git a/plugins/catalog-backend-module-incremental-ingestion/src/run.ts b/plugins/catalog-backend-module-incremental-ingestion/src/run.ts index e99ec7e41a..cfb4c20def 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/src/run.ts +++ b/plugins/catalog-backend-module-incremental-ingestion/src/run.ts @@ -85,7 +85,7 @@ async function main() { }, }); }, - })(), + }), ); await backend.start(); diff --git a/plugins/catalog-backend-module-msgraph/src/module/catalogModuleMicrosoftGraphOrgEntityProvider.test.ts b/plugins/catalog-backend-module-msgraph/src/module/catalogModuleMicrosoftGraphOrgEntityProvider.test.ts index 9f1a4ead8b..96fec41cbe 100644 --- a/plugins/catalog-backend-module-msgraph/src/module/catalogModuleMicrosoftGraphOrgEntityProvider.test.ts +++ b/plugins/catalog-backend-module-msgraph/src/module/catalogModuleMicrosoftGraphOrgEntityProvider.test.ts @@ -14,14 +14,15 @@ * limitations under the License. */ -import { getVoidLogger } from '@backstage/backend-common'; -import { coreServices } from '@backstage/backend-plugin-api'; +import { + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; import { PluginTaskScheduler, TaskScheduleDefinition, } from '@backstage/backend-tasks'; -import { startTestBackend } from '@backstage/backend-test-utils'; -import { ConfigReader } from '@backstage/config'; +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { Duration } from 'luxon'; import { catalogModuleMicrosoftGraphOrgEntityProvider } from './catalogModuleMicrosoftGraphOrgEntityProvider'; @@ -45,7 +46,7 @@ describe('catalogModuleMicrosoftGraphOrgEntityProvider', () => { }, } as unknown as PluginTaskScheduler; - const config = new ConfigReader({ + const config = { catalog: { providers: { microsoftGraphOrg: { @@ -62,16 +63,19 @@ describe('catalogModuleMicrosoftGraphOrgEntityProvider', () => { }, }, }, - }); + }; await startTestBackend({ extensionPoints: [[catalogProcessingExtensionPoint, extensionPoint]], - services: [ - [coreServices.rootConfig, config], - [coreServices.logger, getVoidLogger()], - [coreServices.scheduler, scheduler], + features: [ + catalogModuleMicrosoftGraphOrgEntityProvider(), + mockServices.rootConfig.factory({ data: config }), + createServiceFactory(() => ({ + deps: {}, + service: coreServices.scheduler, + factory: async () => scheduler, + })), ], - features: [catalogModuleMicrosoftGraphOrgEntityProvider()], }); expect(usedSchedule?.frequency).toEqual(Duration.fromISO('PT30M')); diff --git a/plugins/catalog-backend-module-puppetdb/src/module/catalogModulePuppetDbEntityProvider.test.ts b/plugins/catalog-backend-module-puppetdb/src/module/catalogModulePuppetDbEntityProvider.test.ts index c167035917..3ea54d8c8f 100644 --- a/plugins/catalog-backend-module-puppetdb/src/module/catalogModulePuppetDbEntityProvider.test.ts +++ b/plugins/catalog-backend-module-puppetdb/src/module/catalogModulePuppetDbEntityProvider.test.ts @@ -14,14 +14,15 @@ * limitations under the License. */ -import { getVoidLogger } from '@backstage/backend-common'; -import { coreServices } from '@backstage/backend-plugin-api'; +import { + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; import { PluginTaskScheduler, TaskScheduleDefinition, } from '@backstage/backend-tasks'; -import { startTestBackend } from '@backstage/backend-test-utils'; -import { ConfigReader } from '@backstage/config'; +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { catalogModulePuppetDbEntityProvider } from './catalogModulePuppetDbEntityProvider'; import { PuppetDbEntityProvider } from '../providers/PuppetDbEntityProvider'; @@ -44,7 +45,7 @@ describe('catalogModulePuppetDbEntityProvider', () => { }, } as unknown as PluginTaskScheduler; - const config = new ConfigReader({ + const config = { catalog: { providers: { puppetdb: { @@ -56,16 +57,19 @@ describe('catalogModulePuppetDbEntityProvider', () => { }, }, }, - }); + }; await startTestBackend({ extensionPoints: [[catalogProcessingExtensionPoint, extensionPoint]], - services: [ - [coreServices.rootConfig, config], - [coreServices.logger, getVoidLogger()], - [coreServices.scheduler, scheduler], + features: [ + catalogModulePuppetDbEntityProvider(), + mockServices.rootConfig.factory({ data: config }), + createServiceFactory(() => ({ + deps: {}, + service: coreServices.scheduler, + factory: async () => scheduler, + })), ], - features: [catalogModulePuppetDbEntityProvider()], }); expect(usedSchedule?.frequency).toEqual({ minutes: 10 }); diff --git a/plugins/catalog-backend/src/tests/performance/stitchingPerformance.test.ts b/plugins/catalog-backend/src/tests/performance/stitchingPerformance.test.ts index 9cb20d557d..fb2bd06b96 100644 --- a/plugins/catalog-backend/src/tests/performance/stitchingPerformance.test.ts +++ b/plugins/catalog-backend/src/tests/performance/stitchingPerformance.test.ts @@ -180,7 +180,6 @@ describePerformanceTest('stitchingPerformance', () => { const tracker = new Tracker(knex, load); const backend = await startTestBackend({ - services: [staticDatabase(knex)], features: [ catalogPlugin(), createBackendModule({ @@ -201,7 +200,8 @@ describePerformanceTest('stitchingPerformance', () => { }, }); }, - })(), + }), + staticDatabase(knex), ], }); diff --git a/plugins/events-backend-module-aws-sqs/src/service/eventsModuleAwsSqsConsumingEventPublisher.test.ts b/plugins/events-backend-module-aws-sqs/src/service/eventsModuleAwsSqsConsumingEventPublisher.test.ts index 849ad733de..a76817c3c0 100644 --- a/plugins/events-backend-module-aws-sqs/src/service/eventsModuleAwsSqsConsumingEventPublisher.test.ts +++ b/plugins/events-backend-module-aws-sqs/src/service/eventsModuleAwsSqsConsumingEventPublisher.test.ts @@ -14,10 +14,12 @@ * limitations under the License. */ -import { getVoidLogger } from '@backstage/backend-common'; -import { coreServices } from '@backstage/backend-plugin-api'; -import { startTestBackend } from '@backstage/backend-test-utils'; -import { ConfigReader } from '@backstage/config'; +import { + coreServices, + createServiceFactory, + SchedulerService, +} from '@backstage/backend-plugin-api'; +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { eventsExtensionPoint } from '@backstage/plugin-events-node/alpha'; import { TestEventBroker } from '@backstage/plugin-events-backend-test-utils'; import { eventsModuleAwsSqsConsumingEventPublisher } from './eventsModuleAwsSqsConsumingEventPublisher'; @@ -25,31 +27,6 @@ import { AwsSqsConsumingEventPublisher } from '../publisher/AwsSqsConsumingEvent describe('eventsModuleAwsSqsConsumingEventPublisher', () => { it('should be correctly wired and set up', async () => { - const config = new ConfigReader({ - events: { - modules: { - awsSqs: { - awsSqsConsumingEventPublisher: { - topics: { - fake1: { - queue: { - region: 'eu-west-1', - url: 'https://fake1.queue.url', - }, - }, - fake2: { - queue: { - region: 'us-east-1', - url: 'https://fake2.queue.url', - }, - }, - }, - }, - }, - }, - }, - }); - let addedPublishers: AwsSqsConsumingEventPublisher[] | undefined; const extensionPoint = { addPublishers: (publishers: any) => { @@ -59,16 +36,44 @@ describe('eventsModuleAwsSqsConsumingEventPublisher', () => { const scheduler = { scheduleTask: jest.fn(), - }; + } as unknown as SchedulerService; await startTestBackend({ extensionPoints: [[eventsExtensionPoint, extensionPoint]], - services: [ - [coreServices.rootConfig, config], - [coreServices.logger, getVoidLogger()], - [coreServices.scheduler, scheduler], + features: [ + eventsModuleAwsSqsConsumingEventPublisher(), + mockServices.rootConfig.factory({ + data: { + events: { + modules: { + awsSqs: { + awsSqsConsumingEventPublisher: { + topics: { + fake1: { + queue: { + region: 'eu-west-1', + url: 'https://fake1.queue.url', + }, + }, + fake2: { + queue: { + region: 'us-east-1', + url: 'https://fake2.queue.url', + }, + }, + }, + }, + }, + }, + }, + }, + }), + createServiceFactory({ + service: coreServices.scheduler, + deps: {}, + factory: () => scheduler, + }), ], - features: [eventsModuleAwsSqsConsumingEventPublisher()], }); expect(addedPublishers).not.toBeUndefined(); diff --git a/plugins/events-backend-module-azure/src/service/eventsModuleAzureDevOpsEventRouter.test.ts b/plugins/events-backend-module-azure/src/service/eventsModuleAzureDevOpsEventRouter.test.ts index 1ff756a2d2..d67b5eb071 100644 --- a/plugins/events-backend-module-azure/src/service/eventsModuleAzureDevOpsEventRouter.test.ts +++ b/plugins/events-backend-module-azure/src/service/eventsModuleAzureDevOpsEventRouter.test.ts @@ -34,7 +34,6 @@ describe('eventsModuleAzureDevOpsEventRouter', () => { await startTestBackend({ extensionPoints: [[eventsExtensionPoint, extensionPoint]], - services: [], features: [eventsModuleAzureDevOpsEventRouter()], }); diff --git a/plugins/events-backend-module-bitbucket-cloud/src/service/eventsModuleBitbucketCloudEventRouter.test.ts b/plugins/events-backend-module-bitbucket-cloud/src/service/eventsModuleBitbucketCloudEventRouter.test.ts index 17d2252c7b..025d994b4b 100644 --- a/plugins/events-backend-module-bitbucket-cloud/src/service/eventsModuleBitbucketCloudEventRouter.test.ts +++ b/plugins/events-backend-module-bitbucket-cloud/src/service/eventsModuleBitbucketCloudEventRouter.test.ts @@ -34,7 +34,6 @@ describe('eventsModuleBitbucketCloudEventRouter', () => { await startTestBackend({ extensionPoints: [[eventsExtensionPoint, extensionPoint]], - services: [], features: [eventsModuleBitbucketCloudEventRouter()], }); diff --git a/plugins/events-backend-module-gerrit/src/service/eventsModuleGerritEventRouter.test.ts b/plugins/events-backend-module-gerrit/src/service/eventsModuleGerritEventRouter.test.ts index 88ef995966..c11f4c42db 100644 --- a/plugins/events-backend-module-gerrit/src/service/eventsModuleGerritEventRouter.test.ts +++ b/plugins/events-backend-module-gerrit/src/service/eventsModuleGerritEventRouter.test.ts @@ -34,7 +34,6 @@ describe('eventsModuleGerritEventRouter', () => { await startTestBackend({ extensionPoints: [[eventsExtensionPoint, extensionPoint]], - services: [], features: [eventsModuleGerritEventRouter()], }); diff --git a/plugins/events-backend-module-github/src/service/eventsModuleGithubEventRouter.test.ts b/plugins/events-backend-module-github/src/service/eventsModuleGithubEventRouter.test.ts index bfa186c7bc..02151d0dcf 100644 --- a/plugins/events-backend-module-github/src/service/eventsModuleGithubEventRouter.test.ts +++ b/plugins/events-backend-module-github/src/service/eventsModuleGithubEventRouter.test.ts @@ -34,7 +34,6 @@ describe('eventsModuleGithubEventRouter', () => { await startTestBackend({ extensionPoints: [[eventsExtensionPoint, extensionPoint]], - services: [], features: [eventsModuleGithubEventRouter()], }); diff --git a/plugins/events-backend-module-github/src/service/eventsModuleGithubWebhook.test.ts b/plugins/events-backend-module-github/src/service/eventsModuleGithubWebhook.test.ts index f5bb07f0d6..4effa62dd0 100644 --- a/plugins/events-backend-module-github/src/service/eventsModuleGithubWebhook.test.ts +++ b/plugins/events-backend-module-github/src/service/eventsModuleGithubWebhook.test.ts @@ -14,9 +14,7 @@ * limitations under the License. */ -import { coreServices } from '@backstage/backend-plugin-api'; -import { startTestBackend } from '@backstage/backend-test-utils'; -import { ConfigReader } from '@backstage/config'; +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { eventsExtensionPoint } from '@backstage/plugin-events-node/alpha'; import { HttpPostIngressOptions, @@ -47,20 +45,22 @@ describe('eventsModuleGithubWebhook', () => { }, }; - const config = new ConfigReader({ - events: { - modules: { - github: { - webhookSecret: secret, - }, - }, - }, - }); - await startTestBackend({ extensionPoints: [[eventsExtensionPoint, extensionPoint]], - services: [[coreServices.rootConfig, config]], - features: [eventsModuleGithubWebhook()], + features: [ + eventsModuleGithubWebhook(), + mockServices.rootConfig.factory({ + data: { + events: { + modules: { + github: { + webhookSecret: secret, + }, + }, + }, + }, + }), + ], }); expect(addedIngress).not.toBeUndefined(); diff --git a/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabEventRouter.test.ts b/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabEventRouter.test.ts index 86a0df6e68..34a68ccbe4 100644 --- a/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabEventRouter.test.ts +++ b/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabEventRouter.test.ts @@ -34,7 +34,6 @@ describe('eventsModuleGitlabEventRouter', () => { await startTestBackend({ extensionPoints: [[eventsExtensionPoint, extensionPoint]], - services: [], features: [eventsModuleGitlabEventRouter()], }); diff --git a/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabWebhook.test.ts b/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabWebhook.test.ts index 92e803c439..1ab116ee3d 100644 --- a/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabWebhook.test.ts +++ b/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabWebhook.test.ts @@ -14,9 +14,7 @@ * limitations under the License. */ -import { coreServices } from '@backstage/backend-plugin-api'; -import { startTestBackend } from '@backstage/backend-test-utils'; -import { ConfigReader } from '@backstage/config'; +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { eventsExtensionPoint } from '@backstage/plugin-events-node/alpha'; import { HttpPostIngressOptions, @@ -42,20 +40,22 @@ describe('gitlabWebhookEventsModule', () => { }, }; - const config = new ConfigReader({ - events: { - modules: { - gitlab: { - webhookSecret: 'test-secret', - }, - }, - }, - }); - await startTestBackend({ extensionPoints: [[eventsExtensionPoint, extensionPoint]], - services: [[coreServices.rootConfig, config]], - features: [eventsModuleGitlabWebhook()], + features: [ + eventsModuleGitlabWebhook(), + mockServices.rootConfig.factory({ + data: { + events: { + modules: { + gitlab: { + webhookSecret: 'test-secret', + }, + }, + }, + }, + }), + ], }); expect(addedIngress).not.toBeUndefined(); diff --git a/plugins/events-backend/src/service/EventsPlugin.test.ts b/plugins/events-backend/src/service/EventsPlugin.test.ts index bce45c9ef3..e65147ebbb 100644 --- a/plugins/events-backend/src/service/EventsPlugin.test.ts +++ b/plugins/events-backend/src/service/EventsPlugin.test.ts @@ -14,13 +14,13 @@ * limitations under the License. */ -import { errorHandler, getVoidLogger } from '@backstage/backend-common'; -import { ConfigReader } from '@backstage/config'; +import { errorHandler } from '@backstage/backend-common'; import { coreServices, createBackendModule, + createServiceFactory, } from '@backstage/backend-plugin-api'; -import { startTestBackend } from '@backstage/backend-test-utils'; +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { eventsExtensionPoint } from '@backstage/plugin-events-node/alpha'; import { TestEventBroker, @@ -38,14 +38,6 @@ describe('eventPlugin', () => { const publisher = new TestEventPublisher(); const subscriber = new TestEventSubscriber('sub', ['fake']); - const config = new ConfigReader({ - events: { - http: { - topics: ['fake'], - }, - }, - }); - const httpRouter = Router(); httpRouter.use(express.json()); httpRouter.use(errorHandler()); @@ -70,12 +62,25 @@ describe('eventPlugin', () => { await startTestBackend({ extensionPoints: [], - services: [ - [coreServices.rootConfig, config], - [coreServices.httpRouter, httpRouter], - [coreServices.logger, getVoidLogger()], + features: [ + eventsPlugin(), + testModule(), + mockServices.logger.factory(), + mockServices.rootConfig.factory({ + data: { + events: { + http: { + topics: ['fake'], + }, + }, + }, + }), + createServiceFactory({ + service: coreServices.httpRouter, + deps: {}, + factory: async () => httpRouter, + }), ], - features: [eventsPlugin(), testModule()], }); expect(publisher.eventBroker).toBe(eventBroker); diff --git a/plugins/search-backend-module-catalog/src/alpha.test.ts b/plugins/search-backend-module-catalog/src/alpha.test.ts index edd922b7fb..33ac978d41 100644 --- a/plugins/search-backend-module-catalog/src/alpha.test.ts +++ b/plugins/search-backend-module-catalog/src/alpha.test.ts @@ -49,8 +49,8 @@ describe('searchModuleCatalogCollator', () => { }, ], ], - features: [searchModuleCatalogCollator()], - services: [ + features: [ + searchModuleCatalogCollator(), mockServices.rootConfig.factory({ data: { search: { diff --git a/plugins/search-backend-module-explore/src/alpha.test.ts b/plugins/search-backend-module-explore/src/alpha.test.ts index b7a44e4898..4505f86c5e 100644 --- a/plugins/search-backend-module-explore/src/alpha.test.ts +++ b/plugins/search-backend-module-explore/src/alpha.test.ts @@ -34,8 +34,8 @@ describe('searchModuleExploreCollator', () => { extensionPoints: [ [searchIndexRegistryExtensionPoint, extensionPointMock], ], - features: [searchModuleExploreCollator()], - services: [ + features: [ + searchModuleExploreCollator(), mockServices.rootConfig.factory({ data: { search: { diff --git a/plugins/search-backend-module-techdocs/src/alpha.test.ts b/plugins/search-backend-module-techdocs/src/alpha.test.ts index 1e7ef494bb..d65a77a765 100644 --- a/plugins/search-backend-module-techdocs/src/alpha.test.ts +++ b/plugins/search-backend-module-techdocs/src/alpha.test.ts @@ -34,8 +34,8 @@ describe('searchModuleTechDocsCollator', () => { extensionPoints: [ [searchIndexRegistryExtensionPoint, extensionPointMock], ], - features: [searchModuleTechDocsCollator()], - services: [ + features: [ + searchModuleTechDocsCollator(), mockServices.rootConfig.factory({ data: { search: { From 09fea35cd1f738f23f15cb54ef3e3c7457de5fb4 Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Tue, 15 Aug 2023 15:01:58 +0200 Subject: [PATCH 18/22] backend-app-api: use provided service factories Signed-off-by: Vincenzo Scamporlino --- packages/backend-app-api/src/wiring/BackendInitializer.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/backend-app-api/src/wiring/BackendInitializer.ts b/packages/backend-app-api/src/wiring/BackendInitializer.ts index b6f79e19da..93d2f6942a 100644 --- a/packages/backend-app-api/src/wiring/BackendInitializer.ts +++ b/packages/backend-app-api/src/wiring/BackendInitializer.ts @@ -167,7 +167,10 @@ export class BackendInitializer { } async #doStart(): Promise { - this.#serviceHolder = new ServiceRegistry(this.#defaultApiFactories); + this.#serviceHolder = new ServiceRegistry([ + ...this.#defaultApiFactories, + ...this.#providedServiceFactories, + ]); const featureDiscovery = await this.#serviceHolder.get( featureDiscoveryServiceRef, From 32c01a9a430f5099f7f6f9537351b5719f9d410b Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Tue, 15 Aug 2023 15:10:53 +0200 Subject: [PATCH 19/22] remove changeset Signed-off-by: Vincenzo Scamporlino --- .changeset/selfish-pumas-draw.md | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 .changeset/selfish-pumas-draw.md diff --git a/.changeset/selfish-pumas-draw.md b/.changeset/selfish-pumas-draw.md deleted file mode 100644 index 9893b896ba..0000000000 --- a/.changeset/selfish-pumas-draw.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-incremental-ingestion': patch ---- - -Use new backend feature api to customize `rootConfig`. From 29a4738cd90d324006b260360db735c907b745bd Mon Sep 17 00:00:00 2001 From: Vincenzo Scamporlino Date: Tue, 15 Aug 2023 16:28:10 +0200 Subject: [PATCH 20/22] backend-test-utils: detect internal features Signed-off-by: Vincenzo Scamporlino --- .../src/next/wiring/TestBackend.ts | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.ts index 13c05eb61c..97da3543ae 100644 --- a/packages/backend-test-utils/src/next/wiring/TestBackend.ts +++ b/packages/backend-test-utils/src/next/wiring/TestBackend.ts @@ -103,13 +103,16 @@ function createExtensionPointTestModules( `Failed to add feature, invalid type '${feature.$$type}'`, ); } - const internalFeature = feature as InternalBackendFeature; - if (internalFeature.version !== 'v1') { - throw new Error( - `Failed to add feature, invalid version '${internalFeature.version}'`, - ); + + if (isInternalBackendFeature(feature)) { + if (feature.version !== 'v1') { + throw new Error( + `Failed to add feature, invalid version '${feature.version}'`, + ); + } + return feature.getRegistrations(); } - return internalFeature.getRegistrations(); + return []; }); const extensionPointMap = new Map( @@ -287,3 +290,11 @@ function registerTestHooks() { } registerTestHooks(); + +function isInternalBackendFeature( + feature: BackendFeature, +): feature is InternalBackendFeature { + return ( + typeof (feature as InternalBackendFeature).getRegistrations === 'function' + ); +} From d8c8dbf4ef61a65452af2fd00640a94698cff5af Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 15 Aug 2023 17:01:38 +0200 Subject: [PATCH 21/22] Apply suggestions from code review Signed-off-by: Patrik Oldsberg --- .changeset/young-lies-attack.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.changeset/young-lies-attack.md b/.changeset/young-lies-attack.md index ebf6401d17..02a23e38e5 100644 --- a/.changeset/young-lies-attack.md +++ b/.changeset/young-lies-attack.md @@ -1,11 +1,11 @@ --- '@backstage/backend-plugin-api': patch -'@backstage/backend-test-utils': patch -'@backstage/backend-defaults': patch -'@backstage/backend-app-api': patch +'@backstage/backend-test-utils': minor +'@backstage/backend-defaults': minor +'@backstage/backend-app-api': minor --- -**BREAKING**: Removed options from `createBackend`. Service factories are now `BackendFeature`s and should be installed with `backend.add(...)` instead. The following should be migrated: +**BREAKING**: Removed the `services` option from `createBackend`. Service factories are now `BackendFeature`s and should be installed with `backend.add(...)` instead. The following should be migrated: ```ts const backend = createBackend({ services: [myCustomServiceFactory] }); From 738e4df65d893f45d2a491d82228c80d578756b4 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 15 Aug 2023 17:34:56 +0200 Subject: [PATCH 22/22] catalog-backend-module-incremental-ingestion: fix module test Signed-off-by: Patrik Oldsberg --- ...eIncrementalIngestionEntityProvider.test.ts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.test.ts b/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.test.ts index ffb70a3060..ed0c776fa8 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.test.ts +++ b/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.test.ts @@ -14,8 +14,12 @@ * limitations under the License. */ -import { createBackendModule } from '@backstage/backend-plugin-api'; -import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; +import { + coreServices, + createBackendModule, + createServiceFactory, +} from '@backstage/backend-plugin-api'; +import { startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { IncrementalEntityProvider } from '../types'; import { @@ -43,11 +47,11 @@ describe('catalogModuleIncrementalIngestionEntityProvider', () => { [catalogProcessingExtensionPoint, { addEntityProvider }], ], features: [ - mockServices.rootConfig.factory(), - mockServices.database.factory(), - mockServices.httpRouter.factory(), - mockServices.logger.factory(), - mockServices.scheduler.factory(), + createServiceFactory({ + service: coreServices.httpRouter, + deps: {}, + factory: () => ({ use: httpRouterUse }), + }), catalogModuleIncrementalIngestionEntityProvider(), createBackendModule({ pluginId: 'catalog',