Merge pull request #30272 from backstage/blam/move-things
`Actions` / `ActionsRegistry`: Move things around to export as `alpha` services
This commit is contained in:
@@ -20,8 +20,6 @@
|
||||
"license": "Apache-2.0",
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./actions": "./src/entrypoints/actions/index.ts",
|
||||
"./actionsRegistry": "./src/entrypoints/actionsRegistry/index.ts",
|
||||
"./auditor": "./src/entrypoints/auditor/index.ts",
|
||||
"./auth": "./src/entrypoints/auth/index.ts",
|
||||
"./cache": "./src/entrypoints/cache/index.ts",
|
||||
@@ -41,18 +39,13 @@
|
||||
"./scheduler": "./src/entrypoints/scheduler/index.ts",
|
||||
"./urlReader": "./src/entrypoints/urlReader/index.ts",
|
||||
"./userInfo": "./src/entrypoints/userInfo/index.ts",
|
||||
"./alpha": "./src/alpha/index.ts",
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"actions": [
|
||||
"src/entrypoints/actions/index.ts"
|
||||
],
|
||||
"actionsRegistry": [
|
||||
"src/entrypoints/actionsRegistry/index.ts"
|
||||
],
|
||||
"auditor": [
|
||||
"src/entrypoints/auditor/index.ts"
|
||||
],
|
||||
@@ -110,6 +103,9 @@
|
||||
"userInfo": [
|
||||
"src/entrypoints/userInfo/index.ts"
|
||||
],
|
||||
"alpha": [
|
||||
"src/alpha/index.ts"
|
||||
],
|
||||
"package.json": [
|
||||
"package.json"
|
||||
]
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
## API Report File for "@backstage/backend-defaults"
|
||||
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
import { ActionsService } from '@backstage/backend-plugin-api';
|
||||
import { ServiceFactory } from '@backstage/backend-plugin-api';
|
||||
|
||||
// @public (undocumented)
|
||||
export const actionsServiceFactory: ServiceFactory<
|
||||
ActionsService,
|
||||
'plugin',
|
||||
'singleton'
|
||||
>;
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
```
|
||||
+9
-1
@@ -3,7 +3,8 @@
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
import { ActionsRegistryService } from '@backstage/backend-plugin-api';
|
||||
import { ActionsRegistryService } from '@backstage/backend-plugin-api/alpha';
|
||||
import { ActionsService } from '@backstage/backend-plugin-api/alpha';
|
||||
import { ServiceFactory } from '@backstage/backend-plugin-api';
|
||||
|
||||
// @public (undocumented)
|
||||
@@ -13,5 +14,12 @@ export const actionsRegistryServiceFactory: ServiceFactory<
|
||||
'singleton'
|
||||
>;
|
||||
|
||||
// @public (undocumented)
|
||||
export const actionsServiceFactory: ServiceFactory<
|
||||
ActionsService,
|
||||
'plugin',
|
||||
'singleton'
|
||||
>;
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
```
|
||||
@@ -35,12 +35,12 @@ import { schedulerServiceFactory } from '@backstage/backend-defaults/scheduler';
|
||||
import { urlReaderServiceFactory } from '@backstage/backend-defaults/urlReader';
|
||||
import { userInfoServiceFactory } from '@backstage/backend-defaults/userInfo';
|
||||
import { eventsServiceFactory } from '@backstage/plugin-events-node';
|
||||
import { actionsRegistryServiceFactory } from './entrypoints/actionsRegistry';
|
||||
import { actionsServiceFactory } from './entrypoints/actions';
|
||||
|
||||
export const defaultServiceFactories = [
|
||||
import {
|
||||
actionsRegistryServiceFactory,
|
||||
actionsServiceFactory,
|
||||
} from '@backstage/backend-defaults/alpha';
|
||||
|
||||
export const defaultServiceFactories = [
|
||||
auditorServiceFactory,
|
||||
authServiceFactory,
|
||||
cacheServiceFactory,
|
||||
@@ -61,6 +61,10 @@ export const defaultServiceFactories = [
|
||||
userInfoServiceFactory,
|
||||
urlReaderServiceFactory,
|
||||
eventsServiceFactory,
|
||||
|
||||
// alpha services
|
||||
actionsRegistryServiceFactory,
|
||||
actionsServiceFactory,
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
+4
-2
@@ -14,8 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import {
|
||||
ActionsService,
|
||||
ActionsServiceAction,
|
||||
AuthService,
|
||||
BackstageCredentials,
|
||||
DiscoveryService,
|
||||
@@ -24,6 +22,10 @@ import {
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { ResponseError } from '@backstage/errors';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import {
|
||||
ActionsService,
|
||||
ActionsServiceAction,
|
||||
} from '@backstage/backend-plugin-api/alpha';
|
||||
|
||||
export class DefaultActionsService implements ActionsService {
|
||||
private constructor(
|
||||
+6
-4
@@ -21,18 +21,20 @@ import {
|
||||
startTestBackend,
|
||||
} from '@backstage/backend-test-utils';
|
||||
import { actionsRegistryServiceFactory } from '../actionsRegistry';
|
||||
import { httpRouterServiceFactory } from '../httpRouter';
|
||||
import { httpRouterServiceFactory } from '../../../entrypoints/httpRouter';
|
||||
import { actionsServiceFactory } from './actionsServiceFactory';
|
||||
import { setupServer } from 'msw/node';
|
||||
import { rest } from 'msw';
|
||||
import {
|
||||
ActionsServiceAction,
|
||||
coreServices,
|
||||
createBackendPlugin,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { json } from 'express';
|
||||
import Router from 'express-promise-router';
|
||||
import request from 'supertest';
|
||||
import { ActionsServiceAction } from '@backstage/backend-plugin-api/alpha';
|
||||
import { actionsRegistryServiceRef } from '@backstage/backend-plugin-api/alpha';
|
||||
import { actionsServiceRef } from '@backstage/backend-plugin-api/alpha';
|
||||
|
||||
const server = setupServer();
|
||||
|
||||
@@ -201,7 +203,7 @@ describe('actionsServiceFactory', () => {
|
||||
pluginId: 'plugin-with-action',
|
||||
register({ registerInit }) {
|
||||
registerInit({
|
||||
deps: { actionsRegistry: coreServices.actionsRegistry },
|
||||
deps: { actionsRegistry: actionsRegistryServiceRef },
|
||||
async init({ actionsRegistry }) {
|
||||
actionsRegistry.register({
|
||||
name: 'with-validation',
|
||||
@@ -236,7 +238,7 @@ describe('actionsServiceFactory', () => {
|
||||
register({ registerInit }) {
|
||||
registerInit({
|
||||
deps: {
|
||||
actionsService: coreServices.actions,
|
||||
actionsService: actionsServiceRef,
|
||||
router: coreServices.httpRouter,
|
||||
httpAuth: coreServices.httpAuth,
|
||||
},
|
||||
+2
-1
@@ -16,12 +16,13 @@
|
||||
import { createServiceFactory } from '@backstage/backend-plugin-api';
|
||||
import { coreServices } from '@backstage/backend-plugin-api';
|
||||
import { DefaultActionsService } from './DefaultActionsService';
|
||||
import { actionsServiceRef } from '@backstage/backend-plugin-api/alpha';
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export const actionsServiceFactory = createServiceFactory({
|
||||
service: coreServices.actions,
|
||||
service: actionsServiceRef,
|
||||
deps: {
|
||||
discovery: coreServices.discovery,
|
||||
config: coreServices.rootConfig,
|
||||
+4
-2
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
ActionsRegistryActionOptions,
|
||||
ActionsRegistryService,
|
||||
AuthService,
|
||||
HttpAuthService,
|
||||
LoggerService,
|
||||
@@ -26,6 +24,10 @@ import PromiseRouter from 'express-promise-router';
|
||||
import { Router, json } from 'express';
|
||||
import { z, AnyZodObject } from 'zod';
|
||||
import zodToJsonSchema from 'zod-to-json-schema';
|
||||
import {
|
||||
ActionsRegistryActionOptions,
|
||||
ActionsRegistryService,
|
||||
} from '@backstage/backend-plugin-api/alpha';
|
||||
import {
|
||||
ForwardedError,
|
||||
InputError,
|
||||
+10
-12
@@ -13,19 +13,17 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import {
|
||||
coreServices,
|
||||
createBackendPlugin,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { createBackendPlugin } from '@backstage/backend-plugin-api';
|
||||
import {
|
||||
mockCredentials,
|
||||
mockServices,
|
||||
startTestBackend,
|
||||
} from '@backstage/backend-test-utils';
|
||||
import { httpRouterServiceFactory } from '../httpRouter';
|
||||
import { httpRouterServiceFactory } from '../../../entrypoints/httpRouter';
|
||||
import request from 'supertest';
|
||||
import { actionsRegistryServiceFactory } from './actionsRegistryServiceFactory';
|
||||
import { InputError } from '@backstage/errors';
|
||||
import { actionsRegistryServiceRef } from '@backstage/backend-plugin-api/alpha';
|
||||
|
||||
describe('actionsRegistryServiceFactory', () => {
|
||||
const defaultServices = [
|
||||
@@ -43,7 +41,7 @@ describe('actionsRegistryServiceFactory', () => {
|
||||
register(reg) {
|
||||
reg.registerInit({
|
||||
deps: {
|
||||
actionsRegistry: coreServices.actionsRegistry,
|
||||
actionsRegistry: actionsRegistryServiceRef,
|
||||
},
|
||||
async init({ actionsRegistry }) {
|
||||
actionsRegistry.register({
|
||||
@@ -80,7 +78,7 @@ describe('actionsRegistryServiceFactory', () => {
|
||||
register(reg) {
|
||||
reg.registerInit({
|
||||
deps: {
|
||||
actionsRegistry: coreServices.actionsRegistry,
|
||||
actionsRegistry: actionsRegistryServiceRef,
|
||||
},
|
||||
async init({ actionsRegistry }) {
|
||||
actionsRegistry.register({
|
||||
@@ -118,7 +116,7 @@ describe('actionsRegistryServiceFactory', () => {
|
||||
register(reg) {
|
||||
reg.registerInit({
|
||||
deps: {
|
||||
actionsRegistry: coreServices.actionsRegistry,
|
||||
actionsRegistry: actionsRegistryServiceRef,
|
||||
},
|
||||
async init({ actionsRegistry }) {
|
||||
actionsRegistry.register({
|
||||
@@ -187,7 +185,7 @@ describe('actionsRegistryServiceFactory', () => {
|
||||
register(reg) {
|
||||
reg.registerInit({
|
||||
deps: {
|
||||
actionsRegistry: coreServices.actionsRegistry,
|
||||
actionsRegistry: actionsRegistryServiceRef,
|
||||
},
|
||||
async init({ actionsRegistry }) {
|
||||
actionsRegistry.register({
|
||||
@@ -235,7 +233,7 @@ describe('actionsRegistryServiceFactory', () => {
|
||||
register(reg) {
|
||||
reg.registerInit({
|
||||
deps: {
|
||||
actionsRegistry: coreServices.actionsRegistry,
|
||||
actionsRegistry: actionsRegistryServiceRef,
|
||||
},
|
||||
async init({ actionsRegistry }) {
|
||||
actionsRegistry.register({
|
||||
@@ -290,7 +288,7 @@ describe('actionsRegistryServiceFactory', () => {
|
||||
register(reg) {
|
||||
reg.registerInit({
|
||||
deps: {
|
||||
actionsRegistry: coreServices.actionsRegistry,
|
||||
actionsRegistry: actionsRegistryServiceRef,
|
||||
},
|
||||
async init({ actionsRegistry }) {
|
||||
actionsRegistry.register({
|
||||
@@ -349,7 +347,7 @@ describe('actionsRegistryServiceFactory', () => {
|
||||
register(reg) {
|
||||
reg.registerInit({
|
||||
deps: {
|
||||
actionsRegistry: coreServices.actionsRegistry,
|
||||
actionsRegistry: actionsRegistryServiceRef,
|
||||
},
|
||||
async init({ actionsRegistry }) {
|
||||
actionsRegistry.register({
|
||||
+2
-1
@@ -19,12 +19,13 @@ import {
|
||||
createServiceFactory,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { DefaultActionsRegistryService } from './DefaultActionsRegistryService';
|
||||
import { actionsRegistryServiceRef } from '@backstage/backend-plugin-api/alpha';
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export const actionsRegistryServiceFactory = createServiceFactory({
|
||||
service: coreServices.actionsRegistry,
|
||||
service: actionsRegistryServiceRef,
|
||||
deps: {
|
||||
metadata: coreServices.pluginMetadata,
|
||||
httpRouter: coreServices.httpRouter,
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2025 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.
|
||||
*/
|
||||
export { actionsRegistryServiceFactory } from './entrypoints/actionsRegistry';
|
||||
export { actionsServiceFactory } from './entrypoints/actions';
|
||||
@@ -20,7 +20,7 @@
|
||||
"license": "Apache-2.0",
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./alpha": "./src/alpha.ts",
|
||||
"./alpha": "./src/alpha/index.ts",
|
||||
"./testUtils": "./src/testUtils.ts",
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
@@ -29,7 +29,7 @@
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"alpha": [
|
||||
"src/alpha.ts"
|
||||
"src/alpha/index.ts"
|
||||
],
|
||||
"testUtils": [
|
||||
"src/testUtils.ts"
|
||||
|
||||
@@ -3,7 +3,105 @@
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
import { AnyZodObject } from 'zod';
|
||||
import { BackstageCredentials } from '@backstage/backend-plugin-api';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { JSONSchema7 } from 'json-schema';
|
||||
import { JsonValue } from '@backstage/types';
|
||||
import { LoggerService } from '@backstage/backend-plugin-api';
|
||||
import { ServiceRef } from '@backstage/backend-plugin-api';
|
||||
import { z } from 'zod';
|
||||
|
||||
// @alpha (undocumented)
|
||||
export type ActionsRegistryActionContext<TInputSchema extends AnyZodObject> = {
|
||||
input: z.infer<TInputSchema>;
|
||||
logger: LoggerService;
|
||||
credentials: BackstageCredentials;
|
||||
};
|
||||
|
||||
// @alpha (undocumented)
|
||||
export type ActionsRegistryActionOptions<
|
||||
TInputSchema extends AnyZodObject,
|
||||
TOutputSchema extends AnyZodObject,
|
||||
> = {
|
||||
name: string;
|
||||
title: string;
|
||||
description: string;
|
||||
schema: {
|
||||
input: (zod: typeof z) => TInputSchema;
|
||||
output: (zod: typeof z) => TOutputSchema;
|
||||
};
|
||||
attributes?: {
|
||||
destructive?: boolean;
|
||||
idempotent?: boolean;
|
||||
readOnly?: boolean;
|
||||
};
|
||||
action: (context: ActionsRegistryActionContext<TInputSchema>) => Promise<
|
||||
z.infer<TOutputSchema> extends void
|
||||
? void
|
||||
: {
|
||||
output: z.infer<TOutputSchema>;
|
||||
}
|
||||
>;
|
||||
};
|
||||
|
||||
// @alpha (undocumented)
|
||||
export interface ActionsRegistryService {
|
||||
// (undocumented)
|
||||
register<
|
||||
TInputSchema extends AnyZodObject,
|
||||
TOutputSchema extends AnyZodObject,
|
||||
>(
|
||||
options: ActionsRegistryActionOptions<TInputSchema, TOutputSchema>,
|
||||
): void;
|
||||
}
|
||||
|
||||
// @alpha
|
||||
export const actionsRegistryServiceRef: ServiceRef<
|
||||
ActionsRegistryService,
|
||||
'plugin',
|
||||
'singleton'
|
||||
>;
|
||||
|
||||
// @alpha (undocumented)
|
||||
export interface ActionsService {
|
||||
// (undocumented)
|
||||
invoke(opts: {
|
||||
id: string;
|
||||
input?: JsonObject;
|
||||
credentials: BackstageCredentials;
|
||||
}): Promise<{
|
||||
output: JsonValue;
|
||||
}>;
|
||||
// (undocumented)
|
||||
list: (opts: { credentials: BackstageCredentials }) => Promise<{
|
||||
actions: ActionsServiceAction[];
|
||||
}>;
|
||||
}
|
||||
|
||||
// @alpha (undocumented)
|
||||
export type ActionsServiceAction = {
|
||||
id: string;
|
||||
name: string;
|
||||
title: string;
|
||||
description: string;
|
||||
schema: {
|
||||
input: JSONSchema7;
|
||||
output: JSONSchema7;
|
||||
};
|
||||
attributes: {
|
||||
readOnly: boolean;
|
||||
destructive: boolean;
|
||||
idempotent: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
// @alpha
|
||||
export const actionsServiceRef: ServiceRef<
|
||||
ActionsService,
|
||||
'plugin',
|
||||
'singleton'
|
||||
>;
|
||||
|
||||
// @alpha (undocumented)
|
||||
export type BackendFeatureMeta =
|
||||
@@ -23,7 +121,7 @@ export interface InstanceMetadataService {
|
||||
getInstalledFeatures: () => BackendFeatureMeta[];
|
||||
}
|
||||
|
||||
// @alpha
|
||||
// @alpha (undocumented)
|
||||
export const instanceMetadataServiceRef: ServiceRef<
|
||||
InstanceMetadataService,
|
||||
'plugin',
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
import { AnyZodObject } from 'zod';
|
||||
import { AuthorizePermissionRequest } from '@backstage/plugin-permission-common';
|
||||
import { AuthorizePermissionResponse } from '@backstage/plugin-permission-common';
|
||||
import { Config } from '@backstage/config';
|
||||
@@ -13,7 +12,6 @@ import type { Handler } from 'express';
|
||||
import { HumanDuration } from '@backstage/types';
|
||||
import { isChildPath } from '@backstage/cli-common';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { JSONSchema7 } from 'json-schema';
|
||||
import { JsonValue } from '@backstage/types';
|
||||
import { Knex } from 'knex';
|
||||
import { Permission } from '@backstage/plugin-permission-common';
|
||||
@@ -27,84 +25,6 @@ import { QueryPermissionResponse } from '@backstage/plugin-permission-common';
|
||||
import { Readable } from 'stream';
|
||||
import type { Request as Request_2 } from 'express';
|
||||
import type { Response as Response_2 } from 'express';
|
||||
import { z } from 'zod';
|
||||
|
||||
// @public (undocumented)
|
||||
export type ActionsRegistryActionContext<TInputSchema extends AnyZodObject> = {
|
||||
input: z.infer<TInputSchema>;
|
||||
logger: LoggerService;
|
||||
credentials: BackstageCredentials;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export type ActionsRegistryActionOptions<
|
||||
TInputSchema extends AnyZodObject,
|
||||
TOutputSchema extends AnyZodObject,
|
||||
> = {
|
||||
name: string;
|
||||
title: string;
|
||||
description: string;
|
||||
schema: {
|
||||
input: (zod: typeof z) => TInputSchema;
|
||||
output: (zod: typeof z) => TOutputSchema;
|
||||
};
|
||||
attributes?: {
|
||||
destructive?: boolean;
|
||||
idempotent?: boolean;
|
||||
readOnly?: boolean;
|
||||
};
|
||||
action: (context: ActionsRegistryActionContext<TInputSchema>) => Promise<
|
||||
z.infer<TOutputSchema> extends void
|
||||
? void
|
||||
: {
|
||||
output: z.infer<TOutputSchema>;
|
||||
}
|
||||
>;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export interface ActionsRegistryService {
|
||||
// (undocumented)
|
||||
register<
|
||||
TInputSchema extends AnyZodObject,
|
||||
TOutputSchema extends AnyZodObject,
|
||||
>(
|
||||
options: ActionsRegistryActionOptions<TInputSchema, TOutputSchema>,
|
||||
): void;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface ActionsService {
|
||||
// (undocumented)
|
||||
invoke(opts: {
|
||||
id: string;
|
||||
input?: JsonObject;
|
||||
credentials: BackstageCredentials;
|
||||
}): Promise<{
|
||||
output: JsonValue;
|
||||
}>;
|
||||
// (undocumented)
|
||||
list: (opts: { credentials: BackstageCredentials }) => Promise<{
|
||||
actions: ActionsServiceAction[];
|
||||
}>;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export type ActionsServiceAction = {
|
||||
id: string;
|
||||
name: string;
|
||||
title: string;
|
||||
description: string;
|
||||
schema: {
|
||||
input: JSONSchema7;
|
||||
output: JSONSchema7;
|
||||
};
|
||||
attributes: {
|
||||
readOnly: boolean;
|
||||
destructive: boolean;
|
||||
idempotent: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
// @public
|
||||
export interface AuditorService {
|
||||
@@ -285,12 +205,6 @@ export type CacheServiceSetOptions = {
|
||||
// @public
|
||||
export namespace coreServices {
|
||||
const auth: ServiceRef<AuthService, 'plugin', 'singleton'>;
|
||||
const actions: ServiceRef<ActionsService, 'plugin', 'singleton'>;
|
||||
const actionsRegistry: ServiceRef<
|
||||
ActionsRegistryService,
|
||||
'plugin',
|
||||
'singleton'
|
||||
>;
|
||||
const userInfo: ServiceRef<UserInfoService, 'plugin', 'singleton'>;
|
||||
const cache: ServiceRef<CacheService, 'plugin', 'singleton'>;
|
||||
const rootConfig: ServiceRef<RootConfigService, 'root', 'singleton'>;
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2025 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { z, AnyZodObject } from 'zod';
|
||||
import {
|
||||
LoggerService,
|
||||
BackstageCredentials,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
*/
|
||||
export type ActionsRegistryActionContext<TInputSchema extends AnyZodObject> = {
|
||||
input: z.infer<TInputSchema>;
|
||||
logger: LoggerService;
|
||||
credentials: BackstageCredentials;
|
||||
};
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
*/
|
||||
export type ActionsRegistryActionOptions<
|
||||
TInputSchema extends AnyZodObject,
|
||||
TOutputSchema extends AnyZodObject,
|
||||
> = {
|
||||
name: string;
|
||||
title: string;
|
||||
description: string;
|
||||
schema: {
|
||||
input: (zod: typeof z) => TInputSchema;
|
||||
output: (zod: typeof z) => TOutputSchema;
|
||||
};
|
||||
attributes?: {
|
||||
destructive?: boolean;
|
||||
idempotent?: boolean;
|
||||
readOnly?: boolean;
|
||||
};
|
||||
action: (
|
||||
context: ActionsRegistryActionContext<TInputSchema>,
|
||||
) => Promise<
|
||||
z.infer<TOutputSchema> extends void
|
||||
? void
|
||||
: { output: z.infer<TOutputSchema> }
|
||||
>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
*/
|
||||
export interface ActionsRegistryService {
|
||||
register<
|
||||
TInputSchema extends AnyZodObject,
|
||||
TOutputSchema extends AnyZodObject,
|
||||
>(
|
||||
options: ActionsRegistryActionOptions<TInputSchema, TOutputSchema>,
|
||||
): void;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2025 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { JsonObject, JsonValue } from '@backstage/types';
|
||||
import { JSONSchema7 } from 'json-schema';
|
||||
import { BackstageCredentials } from '@backstage/backend-plugin-api';
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
*/
|
||||
export type ActionsServiceAction = {
|
||||
id: string;
|
||||
name: string;
|
||||
title: string;
|
||||
description: string;
|
||||
schema: {
|
||||
input: JSONSchema7;
|
||||
output: JSONSchema7;
|
||||
};
|
||||
attributes: {
|
||||
readOnly: boolean;
|
||||
destructive: boolean;
|
||||
idempotent: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
*/
|
||||
export interface ActionsService {
|
||||
list: (opts: {
|
||||
credentials: BackstageCredentials;
|
||||
}) => Promise<{ actions: ActionsServiceAction[] }>;
|
||||
invoke(opts: {
|
||||
id: string;
|
||||
input?: JsonObject;
|
||||
credentials: BackstageCredentials;
|
||||
}): Promise<{ output: JsonValue }>;
|
||||
}
|
||||
+16
-15
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
* Copyright 2025 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.
|
||||
@@ -14,20 +14,21 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { createServiceRef } from '@backstage/backend-plugin-api';
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL: Instance metadata service.
|
||||
*
|
||||
* @alpha
|
||||
*/
|
||||
export const instanceMetadataServiceRef = createServiceRef<
|
||||
import('./services/definitions/InstanceMetadataService').InstanceMetadataService
|
||||
>({
|
||||
id: 'core.instanceMetadata',
|
||||
});
|
||||
|
||||
export type {
|
||||
BackendFeatureMeta,
|
||||
InstanceMetadataService,
|
||||
} from './services/definitions/InstanceMetadataService';
|
||||
} from './InstanceMetadataService';
|
||||
|
||||
export type {
|
||||
ActionsRegistryService,
|
||||
ActionsRegistryActionOptions,
|
||||
ActionsRegistryActionContext,
|
||||
} from './ActionsRegistryService';
|
||||
|
||||
export type { ActionsService, ActionsServiceAction } from './ActionsService';
|
||||
|
||||
export {
|
||||
actionsRegistryServiceRef,
|
||||
actionsServiceRef,
|
||||
instanceMetadataServiceRef,
|
||||
} from './refs';
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2025 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { createServiceRef } from '@backstage/backend-plugin-api';
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
*/
|
||||
export const instanceMetadataServiceRef = createServiceRef<
|
||||
import('./InstanceMetadataService').InstanceMetadataService
|
||||
>({
|
||||
id: 'core.instanceMetadata',
|
||||
});
|
||||
|
||||
/**
|
||||
* Service for calling distributed actions
|
||||
*
|
||||
* See {@link ActionsService}
|
||||
* and {@link https://backstage.io/docs/backend-system/core-services/actions | the service docs}
|
||||
* for more information.
|
||||
*
|
||||
* @alpha
|
||||
*/
|
||||
export const actionsServiceRef = createServiceRef<
|
||||
import('./ActionsService').ActionsService
|
||||
>({
|
||||
id: 'alpha.core.actions',
|
||||
});
|
||||
|
||||
/**
|
||||
* Service for registering and managing distributed actions.
|
||||
*
|
||||
* See {@link ActionsRegistryService}
|
||||
* and {@link https://backstage.io/docs/backend-system/core-services/actions-registry | the service docs}
|
||||
* for more information.
|
||||
*
|
||||
* @alpha
|
||||
*/
|
||||
export const actionsRegistryServiceRef = createServiceRef<
|
||||
import('./ActionsRegistryService').ActionsRegistryService
|
||||
>({
|
||||
id: 'alpha.core.actionsRegistry',
|
||||
});
|
||||
@@ -35,36 +35,6 @@ export namespace coreServices {
|
||||
id: 'core.auth',
|
||||
});
|
||||
|
||||
/**
|
||||
* Service for calling distributed actions
|
||||
*
|
||||
* See {@link ActionsService}
|
||||
* and {@link https://backstage.io/docs/backend-system/core-services/actions | the service docs}
|
||||
* for more information.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const actions = createServiceRef<
|
||||
import('./ActionsService').ActionsService
|
||||
>({
|
||||
id: 'core.actions',
|
||||
});
|
||||
|
||||
/**
|
||||
* Service for registering and managing distributed actions.
|
||||
*
|
||||
* See {@link ActionsRegistryService}
|
||||
* and {@link https://backstage.io/docs/backend-system/core-services/actions-registry | the service docs}
|
||||
* for more information.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const actionsRegistry = createServiceRef<
|
||||
import('./ActionsRegistryService').ActionsRegistryService
|
||||
>({
|
||||
id: 'core.actionsRegistry',
|
||||
});
|
||||
|
||||
/**
|
||||
* Authenticated user information retrieval.
|
||||
*
|
||||
|
||||
@@ -13,14 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export type {
|
||||
ActionsRegistryService,
|
||||
ActionsRegistryActionOptions,
|
||||
ActionsRegistryActionContext,
|
||||
} from './ActionsRegistryService';
|
||||
|
||||
export type { ActionsService, ActionsServiceAction } from './ActionsService';
|
||||
export type {
|
||||
AuditorService,
|
||||
AuditorServiceCreateEventOptions,
|
||||
|
||||
@@ -21,7 +21,8 @@
|
||||
"license": "Apache-2.0",
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./package.json": "./package.json"
|
||||
"./package.json": "./package.json",
|
||||
"./alpha": "./src/alpha/index.ts"
|
||||
},
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
@@ -29,6 +30,9 @@
|
||||
"*": {
|
||||
"package.json": [
|
||||
"package.json"
|
||||
],
|
||||
"alpha": [
|
||||
"src/alpha/index.ts"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
## API Report File for "@backstage/backend-test-utils"
|
||||
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
import { ActionsRegistryActionOptions } from '@backstage/backend-plugin-api/alpha';
|
||||
import { ActionsRegistryService } from '@backstage/backend-plugin-api/alpha';
|
||||
import { ActionsService } from '@backstage/backend-plugin-api/alpha';
|
||||
import { ActionsServiceAction } from '@backstage/backend-plugin-api/alpha';
|
||||
import { AnyZodObject } from 'zod';
|
||||
import { BackstageCredentials } from '@backstage/backend-plugin-api';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { JsonValue } from '@backstage/types';
|
||||
import { LoggerService } from '@backstage/backend-plugin-api';
|
||||
import { ServiceFactory } from '@backstage/backend-plugin-api';
|
||||
|
||||
// @alpha (undocumented)
|
||||
export function actionsRegistryServiceMock(options?: {
|
||||
logger: LoggerService;
|
||||
}): MockActionsRegistry;
|
||||
|
||||
// @alpha (undocumented)
|
||||
export namespace actionsRegistryServiceMock {
|
||||
const // (undocumented)
|
||||
factory: () => ServiceFactory<
|
||||
ActionsRegistryService,
|
||||
'plugin',
|
||||
'singleton'
|
||||
>;
|
||||
const // (undocumented)
|
||||
mock: (
|
||||
partialImpl?: Partial<ActionsRegistryService> | undefined,
|
||||
) => ServiceMock<ActionsRegistryService>;
|
||||
}
|
||||
|
||||
// @alpha (undocumented)
|
||||
export namespace actionsServiceMock {
|
||||
const // (undocumented)
|
||||
factory: () => ServiceFactory<ActionsService, 'plugin', 'singleton'>;
|
||||
const // (undocumented)
|
||||
mock: (
|
||||
partialImpl?: Partial<ActionsService> | undefined,
|
||||
) => ServiceMock<ActionsService>;
|
||||
}
|
||||
|
||||
// @alpha
|
||||
export class MockActionsRegistry
|
||||
implements ActionsRegistryService, ActionsService
|
||||
{
|
||||
// (undocumented)
|
||||
readonly actions: Map<string, ActionsRegistryActionOptions<any, any>>;
|
||||
// (undocumented)
|
||||
static create(opts: { logger: LoggerService }): MockActionsRegistry;
|
||||
// (undocumented)
|
||||
invoke(opts: {
|
||||
id: string;
|
||||
input?: JsonObject;
|
||||
credentials?: BackstageCredentials;
|
||||
}): Promise<{
|
||||
output: JsonValue;
|
||||
}>;
|
||||
// (undocumented)
|
||||
list(): Promise<{
|
||||
actions: ActionsServiceAction[];
|
||||
}>;
|
||||
// (undocumented)
|
||||
register<
|
||||
TInputSchema extends AnyZodObject,
|
||||
TOutputSchema extends AnyZodObject,
|
||||
>(options: ActionsRegistryActionOptions<TInputSchema, TOutputSchema>): void;
|
||||
}
|
||||
|
||||
// @alpha (undocumented)
|
||||
export type ServiceMock<TService> = {
|
||||
factory: ServiceFactory<TService>;
|
||||
} & {
|
||||
[Key in keyof TService]: TService[Key] extends (
|
||||
...args: infer Args
|
||||
) => infer Return
|
||||
? TService[Key] & jest.MockInstance<Return, Args>
|
||||
: TService[Key];
|
||||
};
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
```
|
||||
@@ -3,11 +3,6 @@
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
import { ActionsRegistryActionOptions } from '@backstage/backend-plugin-api';
|
||||
import { ActionsRegistryService } from '@backstage/backend-plugin-api';
|
||||
import { ActionsService } from '@backstage/backend-plugin-api';
|
||||
import { ActionsServiceAction } from '@backstage/backend-plugin-api';
|
||||
import { AnyZodObject } from 'zod';
|
||||
import { AuditorService } from '@backstage/backend-plugin-api';
|
||||
import { AuthorizeResult } from '@backstage/plugin-permission-common';
|
||||
import { AuthService } from '@backstage/backend-plugin-api';
|
||||
@@ -29,7 +24,6 @@ import { ExtensionPoint } from '@backstage/backend-plugin-api';
|
||||
import { HttpAuthService } from '@backstage/backend-plugin-api';
|
||||
import { HttpRouterService } from '@backstage/backend-plugin-api';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { JsonValue } from '@backstage/types';
|
||||
import Keyv from 'keyv';
|
||||
import { Knex } from 'knex';
|
||||
import { LifecycleService } from '@backstage/backend-plugin-api';
|
||||
@@ -60,33 +54,6 @@ export interface CreateMockDirectoryOptions {
|
||||
mockOsTmpDir?: boolean;
|
||||
}
|
||||
|
||||
// @public
|
||||
export class MockActionsRegistry
|
||||
implements ActionsRegistryService, ActionsService
|
||||
{
|
||||
// (undocumented)
|
||||
readonly actions: Map<string, ActionsRegistryActionOptions<any, any>>;
|
||||
// (undocumented)
|
||||
static create(opts: { logger: LoggerService }): MockActionsRegistry;
|
||||
// (undocumented)
|
||||
invoke(opts: {
|
||||
id: string;
|
||||
input?: JsonObject;
|
||||
credentials?: BackstageCredentials;
|
||||
}): Promise<{
|
||||
output: JsonValue;
|
||||
}>;
|
||||
// (undocumented)
|
||||
list(): Promise<{
|
||||
actions: ActionsServiceAction[];
|
||||
}>;
|
||||
// (undocumented)
|
||||
register<
|
||||
TInputSchema extends AnyZodObject,
|
||||
TOutputSchema extends AnyZodObject,
|
||||
>(options: ActionsRegistryActionOptions<TInputSchema, TOutputSchema>): void;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export namespace mockCredentials {
|
||||
export function limitedUser(
|
||||
@@ -195,32 +162,6 @@ export function mockErrorHandler(): ErrorRequestHandler<
|
||||
|
||||
// @public
|
||||
export namespace mockServices {
|
||||
// (undocumented)
|
||||
export namespace actions {
|
||||
const // (undocumented)
|
||||
factory: () => ServiceFactory<ActionsService, 'plugin', 'singleton'>;
|
||||
const // (undocumented)
|
||||
mock: (
|
||||
partialImpl?: Partial<ActionsService> | undefined,
|
||||
) => ServiceMock<ActionsService>;
|
||||
}
|
||||
// (undocumented)
|
||||
export function actionsRegistry(options?: {
|
||||
logger: LoggerService;
|
||||
}): MockActionsRegistry;
|
||||
// (undocumented)
|
||||
export namespace actionsRegistry {
|
||||
const // (undocumented)
|
||||
factory: () => ServiceFactory<
|
||||
ActionsRegistryService,
|
||||
'plugin',
|
||||
'singleton'
|
||||
>;
|
||||
const // (undocumented)
|
||||
mock: (
|
||||
partialImpl?: Partial<ActionsRegistryService> | undefined,
|
||||
) => ServiceMock<ActionsRegistryService>;
|
||||
}
|
||||
// (undocumented)
|
||||
export namespace auditor {
|
||||
const // (undocumented)
|
||||
|
||||
-1
@@ -14,5 +14,4 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export * from './wiring';
|
||||
export * from './services';
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2025 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { mockServices } from '../../services';
|
||||
import { LoggerService } from '@backstage/backend-plugin-api';
|
||||
import { MockActionsRegistry } from './MockActionsRegistry';
|
||||
import { simpleMock } from './simpleMock';
|
||||
import {
|
||||
ActionsRegistryService,
|
||||
actionsRegistryServiceRef,
|
||||
} from '@backstage/backend-plugin-api/alpha';
|
||||
import { actionsRegistryServiceFactory } from '@backstage/backend-defaults/alpha';
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
*/
|
||||
export function actionsRegistryServiceMock(options?: {
|
||||
logger: LoggerService;
|
||||
}): MockActionsRegistry {
|
||||
return MockActionsRegistry.create({
|
||||
logger: options?.logger ?? mockServices.logger.mock(),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
*/
|
||||
export namespace actionsRegistryServiceMock {
|
||||
export const factory = () => actionsRegistryServiceFactory;
|
||||
|
||||
export const mock = simpleMock<ActionsRegistryService>(
|
||||
actionsRegistryServiceRef,
|
||||
() => ({
|
||||
register: jest.fn(),
|
||||
}),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2025 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { simpleMock } from './simpleMock';
|
||||
import {
|
||||
ActionsService,
|
||||
actionsServiceRef,
|
||||
} from '@backstage/backend-plugin-api/alpha';
|
||||
import { actionsServiceFactory } from '@backstage/backend-defaults/alpha';
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
*/
|
||||
export namespace actionsServiceMock {
|
||||
export const factory = () => actionsServiceFactory;
|
||||
|
||||
export const mock = simpleMock<ActionsService>(actionsServiceRef, () => ({
|
||||
invoke: jest.fn(),
|
||||
list: jest.fn(),
|
||||
}));
|
||||
}
|
||||
+16
-12
@@ -17,15 +17,19 @@ import {
|
||||
coreServices,
|
||||
createBackendPlugin,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { startTestBackend } from '../wiring';
|
||||
import { mockServices } from './mockServices';
|
||||
import { mockCredentials } from './mockCredentials';
|
||||
import { startTestBackend } from '../../wiring';
|
||||
import { actionsRegistryServiceMock } from './ActionsRegistryServiceMock';
|
||||
import { mockCredentials } from '../../services';
|
||||
import { Router } from 'express';
|
||||
import supertest from 'supertest';
|
||||
import {
|
||||
actionsRegistryServiceRef,
|
||||
actionsServiceRef,
|
||||
} from '@backstage/backend-plugin-api/alpha';
|
||||
|
||||
describe('MockActionsRegistry', () => {
|
||||
it('should be able to register and invoke actions', async () => {
|
||||
const registry = mockServices.actionsRegistry();
|
||||
const registry = actionsRegistryServiceMock();
|
||||
|
||||
registry.register({
|
||||
name: 'my-demo-action',
|
||||
@@ -53,7 +57,7 @@ describe('MockActionsRegistry', () => {
|
||||
});
|
||||
|
||||
it('should throw an error when the input is invalid to the action', async () => {
|
||||
const registry = mockServices.actionsRegistry();
|
||||
const registry = actionsRegistryServiceMock();
|
||||
|
||||
registry.register({
|
||||
name: 'my-demo-action',
|
||||
@@ -72,7 +76,7 @@ describe('MockActionsRegistry', () => {
|
||||
});
|
||||
|
||||
it('should throw an error when the action is not found', async () => {
|
||||
const registry = mockServices.actionsRegistry();
|
||||
const registry = actionsRegistryServiceMock();
|
||||
|
||||
await expect(registry.invoke({ id: 'test' })).rejects.toThrow(
|
||||
'Action "test" not found, available actions: none',
|
||||
@@ -80,7 +84,7 @@ describe('MockActionsRegistry', () => {
|
||||
});
|
||||
|
||||
it('should throw an error when the action is not found with recommended actions', async () => {
|
||||
const registry = mockServices.actionsRegistry();
|
||||
const registry = actionsRegistryServiceMock();
|
||||
|
||||
registry.register({
|
||||
name: 'my-demo-action',
|
||||
@@ -99,7 +103,7 @@ describe('MockActionsRegistry', () => {
|
||||
});
|
||||
|
||||
it('should throw an error when the output is invalid', async () => {
|
||||
const registry = mockServices.actionsRegistry();
|
||||
const registry = actionsRegistryServiceMock();
|
||||
|
||||
registry.register({
|
||||
name: 'my-demo-action',
|
||||
@@ -119,7 +123,7 @@ describe('MockActionsRegistry', () => {
|
||||
});
|
||||
|
||||
it('should list the actions correctly', async () => {
|
||||
const registry = mockServices.actionsRegistry();
|
||||
const registry = actionsRegistryServiceMock();
|
||||
|
||||
registry.register({
|
||||
name: 'my-demo-action',
|
||||
@@ -165,13 +169,13 @@ describe('MockActionsRegistry', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('mockServices.actions + mockService.actionsRegistry', () => {
|
||||
describe('actionsRegistryServiceMock + mockService.actionsRegistry', () => {
|
||||
it('should be able to register and invoke actions', async () => {
|
||||
const pluginWithAction = createBackendPlugin({
|
||||
pluginId: 'my-plugin',
|
||||
register(reg) {
|
||||
reg.registerInit({
|
||||
deps: { actionsRegistry: coreServices.actionsRegistry },
|
||||
deps: { actionsRegistry: actionsRegistryServiceRef },
|
||||
async init({ actionsRegistry }) {
|
||||
actionsRegistry.register({
|
||||
name: 'test',
|
||||
@@ -196,7 +200,7 @@ describe('MockActionsRegistry', () => {
|
||||
register(reg) {
|
||||
reg.registerInit({
|
||||
deps: {
|
||||
actions: coreServices.actions,
|
||||
actions: actionsServiceRef,
|
||||
router: coreServices.httpRouter,
|
||||
},
|
||||
async init({ actions, router }) {
|
||||
+8
-6
@@ -14,10 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import {
|
||||
ActionsRegistryActionOptions,
|
||||
ActionsRegistryService,
|
||||
ActionsService,
|
||||
ActionsServiceAction,
|
||||
BackstageCredentials,
|
||||
LoggerService,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
@@ -25,7 +21,13 @@ import { ForwardedError, InputError, NotFoundError } from '@backstage/errors';
|
||||
import { JsonObject, JsonValue } from '@backstage/types';
|
||||
import { z, AnyZodObject } from 'zod';
|
||||
import zodToJsonSchema from 'zod-to-json-schema';
|
||||
import { mockCredentials } from './mockCredentials';
|
||||
import { mockCredentials } from '../../services';
|
||||
import {
|
||||
ActionsRegistryActionOptions,
|
||||
ActionsRegistryService,
|
||||
ActionsService,
|
||||
ActionsServiceAction,
|
||||
} from '@backstage/backend-plugin-api/alpha';
|
||||
|
||||
/**
|
||||
* A mock implementation of the ActionsRegistryService and ActionsService that can be used in tests.
|
||||
@@ -58,7 +60,7 @@ import { mockCredentials } from './mockCredentials';
|
||||
* expect(result).toEqual({ output: { name: 'test' } });
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
* @alpha
|
||||
*/
|
||||
export class MockActionsRegistry
|
||||
implements ActionsRegistryService, ActionsService
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 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.
|
||||
*/
|
||||
|
||||
export { actionsRegistryServiceMock } from './ActionsRegistryServiceMock';
|
||||
export { MockActionsRegistry } from './MockActionsRegistry';
|
||||
export { actionsServiceMock } from './ActionsServiceMock';
|
||||
export { type ServiceMock } from './simpleMock';
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2025 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import {
|
||||
createServiceFactory,
|
||||
ServiceFactory,
|
||||
ServiceRef,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
|
||||
/** @alpha */
|
||||
export type ServiceMock<TService> = {
|
||||
factory: ServiceFactory<TService>;
|
||||
} & {
|
||||
[Key in keyof TService]: TService[Key] extends (
|
||||
...args: infer Args
|
||||
) => infer Return
|
||||
? TService[Key] & jest.MockInstance<Return, Args>
|
||||
: TService[Key];
|
||||
};
|
||||
|
||||
/** @internal */
|
||||
export function simpleMock<TService>(
|
||||
ref: ServiceRef<TService, any>,
|
||||
mockFactory: () => jest.Mocked<TService>,
|
||||
): (partialImpl?: Partial<TService>) => ServiceMock<TService> {
|
||||
return partialImpl => {
|
||||
const mock = mockFactory();
|
||||
if (partialImpl) {
|
||||
for (const [key, impl] of Object.entries(partialImpl)) {
|
||||
if (typeof impl === 'function') {
|
||||
(mock as any)[key].mockImplementation(impl);
|
||||
} else {
|
||||
(mock as any)[key] = impl;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Object.assign(mock, {
|
||||
factory: createServiceFactory({
|
||||
service: ref,
|
||||
deps: {},
|
||||
factory: () => mock,
|
||||
}),
|
||||
}) as ServiceMock<TService>;
|
||||
};
|
||||
}
|
||||
@@ -24,5 +24,6 @@ export * from './cache';
|
||||
export * from './database';
|
||||
export * from './msw';
|
||||
export * from './filesystem';
|
||||
export * from './next';
|
||||
export * from './services';
|
||||
export * from './wiring';
|
||||
export { mockErrorHandler } from './util';
|
||||
|
||||
+2
-2
@@ -13,6 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { mockServices, type ServiceMock } from './mockServices';
|
||||
export { mockServices } from './mockServices';
|
||||
export { mockCredentials } from './mockCredentials';
|
||||
export { type MockActionsRegistry } from './MockActionsRegistry';
|
||||
export { type ServiceMock } from './simpleMock';
|
||||
+1
-62
@@ -55,10 +55,8 @@ import { MockRootLoggerService } from './MockRootLoggerService';
|
||||
import { MockUserInfoService } from './MockUserInfoService';
|
||||
import { mockCredentials } from './mockCredentials';
|
||||
import { MockEventsService } from './MockEventsService';
|
||||
import { actionsServiceFactory } from '@backstage/backend-defaults/actions';
|
||||
import { actionsRegistryServiceFactory } from '@backstage/backend-defaults/actionsRegistry';
|
||||
import { MockPermissionsService } from './MockPermissionsService';
|
||||
import { MockActionsRegistry } from './MockActionsRegistry';
|
||||
import { simpleMock } from './simpleMock';
|
||||
|
||||
/** @internal */
|
||||
function createLoggerMock() {
|
||||
@@ -95,43 +93,6 @@ function simpleFactoryWithOptions<
|
||||
((...options: TOptions) => ServiceFactory<TService, TScope>);
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export type ServiceMock<TService> = {
|
||||
factory: ServiceFactory<TService>;
|
||||
} & {
|
||||
[Key in keyof TService]: TService[Key] extends (
|
||||
...args: infer Args
|
||||
) => infer Return
|
||||
? TService[Key] & jest.MockInstance<Return, Args>
|
||||
: TService[Key];
|
||||
};
|
||||
|
||||
/** @internal */
|
||||
function simpleMock<TService>(
|
||||
ref: ServiceRef<TService, any>,
|
||||
mockFactory: () => jest.Mocked<TService>,
|
||||
): (partialImpl?: Partial<TService>) => ServiceMock<TService> {
|
||||
return partialImpl => {
|
||||
const mock = mockFactory();
|
||||
if (partialImpl) {
|
||||
for (const [key, impl] of Object.entries(partialImpl)) {
|
||||
if (typeof impl === 'function') {
|
||||
(mock as any)[key].mockImplementation(impl);
|
||||
} else {
|
||||
(mock as any)[key] = impl;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Object.assign(mock, {
|
||||
factory: createServiceFactory({
|
||||
service: ref,
|
||||
deps: {},
|
||||
factory: () => mock,
|
||||
}),
|
||||
}) as ServiceMock<TService>;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock implementations of the core services, to be used in tests.
|
||||
*
|
||||
@@ -553,28 +514,6 @@ export namespace mockServices {
|
||||
search: jest.fn(),
|
||||
}));
|
||||
}
|
||||
export namespace actions {
|
||||
export const factory = () => actionsServiceFactory;
|
||||
export const mock = simpleMock(coreServices.actions, () => ({
|
||||
list: jest.fn(),
|
||||
invoke: jest.fn(),
|
||||
}));
|
||||
}
|
||||
|
||||
export function actionsRegistry(options?: {
|
||||
logger: LoggerService;
|
||||
}): MockActionsRegistry {
|
||||
return MockActionsRegistry.create({
|
||||
logger: options?.logger ?? mockServices.logger.mock(),
|
||||
});
|
||||
}
|
||||
|
||||
export namespace actionsRegistry {
|
||||
export const factory = () => actionsRegistryServiceFactory;
|
||||
export const mock = simpleMock(coreServices.actionsRegistry, () => ({
|
||||
register: jest.fn(),
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a functional mock implementation of the
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2025 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import {
|
||||
createServiceFactory,
|
||||
ServiceFactory,
|
||||
ServiceRef,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
|
||||
/** @public */
|
||||
export type ServiceMock<TService> = {
|
||||
factory: ServiceFactory<TService>;
|
||||
} & {
|
||||
[Key in keyof TService]: TService[Key] extends (
|
||||
...args: infer Args
|
||||
) => infer Return
|
||||
? TService[Key] & jest.MockInstance<Return, Args>
|
||||
: TService[Key];
|
||||
};
|
||||
|
||||
/** @internal */
|
||||
export function simpleMock<TService>(
|
||||
ref: ServiceRef<TService, any>,
|
||||
mockFactory: () => jest.Mocked<TService>,
|
||||
): (partialImpl?: Partial<TService>) => ServiceMock<TService> {
|
||||
return partialImpl => {
|
||||
const mock = mockFactory();
|
||||
if (partialImpl) {
|
||||
for (const [key, impl] of Object.entries(partialImpl)) {
|
||||
if (typeof impl === 'function') {
|
||||
(mock as any)[key].mockImplementation(impl);
|
||||
} else {
|
||||
(mock as any)[key] = impl;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Object.assign(mock, {
|
||||
factory: createServiceFactory({
|
||||
service: ref,
|
||||
deps: {},
|
||||
factory: () => mock,
|
||||
}),
|
||||
}) as ServiceMock<TService>;
|
||||
};
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter';
|
||||
import { mockServices } from '../next';
|
||||
import { mockServices } from '../services';
|
||||
|
||||
/**
|
||||
* A mock for error handler middleware that can be used in router tests.
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ import { defaultServiceFactories } from './TestBackend';
|
||||
// This is a relative import in order to make sure that the implementation is duplicated
|
||||
// rather than leading to an import from @backstage/backend-app-api.
|
||||
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
|
||||
import { ServiceRegistry } from '../../../../backend-app-api/src/wiring/ServiceRegistry';
|
||||
import { ServiceRegistry } from '../../../backend-app-api/src/wiring/ServiceRegistry';
|
||||
|
||||
/**
|
||||
* Options for {@link ServiceFactoryTester}.
|
||||
+9
-3
@@ -31,7 +31,7 @@ import express from 'express';
|
||||
import {
|
||||
InternalBackendFeature,
|
||||
InternalBackendRegistrations,
|
||||
} from '../../../../backend-plugin-api/src/wiring/types';
|
||||
} from '../../../backend-plugin-api/src/wiring/types';
|
||||
import {
|
||||
DefaultRootHttpRouter,
|
||||
ExtendedHttpServer,
|
||||
@@ -40,6 +40,10 @@ import {
|
||||
createHttpServer,
|
||||
} from '@backstage/backend-defaults/rootHttpRouter';
|
||||
import { HostDiscovery } from '@backstage/backend-defaults/discovery';
|
||||
import {
|
||||
actionsRegistryServiceMock,
|
||||
actionsServiceMock,
|
||||
} from '../alpha/services';
|
||||
|
||||
/** @public */
|
||||
export interface TestBackendOptions<TExtensionPoints extends any[]> {
|
||||
@@ -84,8 +88,10 @@ export const defaultServiceFactories = [
|
||||
mockServices.userInfo.factory(),
|
||||
mockServices.urlReader.factory(),
|
||||
mockServices.events.factory(),
|
||||
mockServices.actionsRegistry.factory(),
|
||||
mockServices.actions.factory(),
|
||||
|
||||
// Alpha services
|
||||
actionsRegistryServiceMock.factory(),
|
||||
actionsServiceMock.factory(),
|
||||
];
|
||||
|
||||
/**
|
||||
Reference in New Issue
Block a user