chore: added the ability to pull actions from actions registry

Signed-off-by: benjdlambert <ben@blam.sh>
This commit is contained in:
benjdlambert
2025-09-12 08:58:17 +02:00
parent 987cd8a6f5
commit e934a27775
3 changed files with 53 additions and 2 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend': patch
---
Updating `catalog:get-catalog-entity` action to be `readOnly` and non destructive
@@ -56,6 +56,7 @@ import {
convertFiltersToRecord,
convertGlobalsToRecord,
} from './util/templating';
import { actionsServiceRef } from '@backstage/backend-plugin-api/alpha';
/**
* Scaffolder plugin
@@ -139,6 +140,7 @@ export const scaffolderPlugin = createBackendPlugin({
auditor: coreServices.auditor,
catalog: catalogServiceRef,
events: eventsServiceRef,
actionsRegistry: actionsServiceRef,
},
async init({
logger,
@@ -153,6 +155,7 @@ export const scaffolderPlugin = createBackendPlugin({
permissions,
events,
auditor,
actionsRegistry,
}) {
const log = loggerToWinstonLogger(logger);
const integrations = ScmIntegrations.fromConfig(config);
@@ -222,6 +225,7 @@ export const scaffolderPlugin = createBackendPlugin({
additionalWorkspaceProviders,
events,
auditor,
actionsRegistry,
});
httpRouter.use(router);
},
@@ -26,6 +26,7 @@ import {
resolveSafeChildPath,
SchedulerService,
} from '@backstage/backend-plugin-api';
import { Schema } from 'jsonschema';
import {
CompoundEntityRef,
Entity,
@@ -131,6 +132,8 @@ import {
} from './rules';
import { TaskFilters } from '@backstage/plugin-scaffolder-node';
import { ActionsService } from '@backstage/backend-plugin-api/alpha';
import { isObject } from 'lodash';
/**
* RouterOptions
@@ -163,6 +166,7 @@ export interface RouterOptions {
events?: EventsService;
auditor?: AuditorService;
autocompleteHandlers?: Record<string, AutocompleteHandler>;
actionsRegistry: ActionsService;
}
function isSupportedTemplate(entity: TemplateEntityV1beta3) {
@@ -198,7 +202,7 @@ export async function createRouter(
config,
database,
catalog,
actions,
actions = [],
scheduler,
additionalTemplateFilters,
additionalTemplateGlobals,
@@ -210,6 +214,7 @@ export async function createRouter(
auth,
httpAuth,
auditor,
actionsRegistry,
} = options;
const concurrentTasksLimit =
@@ -301,7 +306,44 @@ export async function createRouter(
workers.push(worker);
}
actions?.forEach(action => actionRegistry.register(action));
// TODO(blam): it's a little unfortunate that you have to restart the scaffolder
// backend in order to pick these up. We should really just make `ActionsRegistry.get()` async
// and then we can move this logic into the there instead.
const { actions: distributedActions } = await actionsRegistry.list({
credentials: await auth.getOwnServiceCredentials(),
});
for (const action of actions) {
actionRegistry.register(action);
}
for (const action of distributedActions) {
actionRegistry.register({
id: action.id,
description: action.description,
examples: [],
supportsDryRun:
action.attributes?.readOnly === true &&
action.attributes?.destructive === false,
handler: async ctx => {
const { output } = await actionsRegistry.invoke({
id: action.id,
input: ctx.input,
credentials: await ctx.getInitiatorCredentials(),
});
if (isObject(output)) {
for (const [key, value] of Object.entries(output)) {
ctx.output(key as keyof typeof output, value);
}
}
},
schema: {
input: action.schema.input as Schema,
output: action.schema.output as Schema,
},
});
}
const launchWorkers = () => workers.forEach(worker => worker.start());