@backstage/plugin-scaffolder-backend 3.1.4 → 3.2.0-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +61 -3
- package/dist/ScaffolderPlugin.cjs.js +12 -2
- package/dist/ScaffolderPlugin.cjs.js.map +1 -1
- package/dist/actions/createDryRunTemplateAction.cjs.js +110 -0
- package/dist/actions/createDryRunTemplateAction.cjs.js.map +1 -0
- package/dist/actions/createListScaffolderActionsAction.cjs.js +60 -0
- package/dist/actions/createListScaffolderActionsAction.cjs.js.map +1 -0
- package/dist/actions/index.cjs.js +18 -0
- package/dist/actions/index.cjs.js.map +1 -0
- package/dist/actions/listScaffolderTasksAction.cjs.js +80 -0
- package/dist/actions/listScaffolderTasksAction.cjs.js.map +1 -0
- package/dist/schema/openapi/generated/router.cjs.js +29 -11
- package/dist/schema/openapi/generated/router.cjs.js.map +1 -1
- package/dist/service/router.cjs.js +67 -0
- package/dist/service/router.cjs.js.map +1 -1
- package/package.json +19 -33
package/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,70 @@
|
|
|
1
1
|
# @backstage/plugin-scaffolder-backend
|
|
2
2
|
|
|
3
|
-
## 3.
|
|
3
|
+
## 3.2.0-next.2
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- e8736ea: Added secrets schema validation for task creation, retry, and dry-run endpoints. When a template defines `spec.secrets.schema`, the API validates provided secrets against the schema and returns a `400` error if validation fails.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- 30ff981: Fixed a security vulnerability where secrets could bypass log redaction when transformed through Nunjucks filters in scaffolder templates.
|
|
12
|
+
- Updated dependencies
|
|
13
|
+
- @backstage/backend-plugin-api@1.8.0-next.1
|
|
14
|
+
- @backstage/integration@2.0.0-next.2
|
|
15
|
+
- @backstage/plugin-scaffolder-common@2.0.0-next.2
|
|
16
|
+
- @backstage/backend-openapi-utils@0.6.7-next.1
|
|
17
|
+
- @backstage/plugin-catalog-node@2.1.0-next.2
|
|
18
|
+
- @backstage/plugin-events-node@0.4.20-next.1
|
|
19
|
+
- @backstage/plugin-permission-node@0.10.11-next.1
|
|
20
|
+
- @backstage/plugin-scaffolder-node@0.13.0-next.2
|
|
21
|
+
|
|
22
|
+
## 3.2.0-next.1
|
|
23
|
+
|
|
24
|
+
### Minor Changes
|
|
25
|
+
|
|
26
|
+
- c9b11eb: Added a new `list-scaffolder-tasks` action that allows querying scaffolder tasks with optional ownership filtering and pagination support
|
|
27
|
+
- 0fbcf23: Migrated OpenAPI schemas to 3.1.
|
|
28
|
+
- 7695dd2: Added a new `list-scaffolder-actions` action that returns all installed scaffolder actions with their schemas and examples
|
|
29
|
+
|
|
30
|
+
### Patch Changes
|
|
31
|
+
|
|
32
|
+
- e27bd4e: Removed `@backstage/plugin-scaffolder-backend-module-bitbucket` from `package.json` as the package itself has been deprecated and the code deleted.
|
|
33
|
+
- ccc20cf: create scaffolder MCP action to dry run a provided scaffolder template
|
|
34
|
+
- Updated dependencies
|
|
35
|
+
- @backstage/integration@2.0.0-next.1
|
|
36
|
+
- @backstage/plugin-scaffolder-common@2.0.0-next.1
|
|
37
|
+
- @backstage/plugin-scaffolder-node@0.13.0-next.1
|
|
38
|
+
- @backstage/plugin-catalog-node@2.1.0-next.1
|
|
39
|
+
- @backstage/backend-openapi-utils@0.6.7-next.0
|
|
40
|
+
- @backstage/backend-plugin-api@1.7.1-next.0
|
|
41
|
+
- @backstage/catalog-model@1.7.6
|
|
42
|
+
- @backstage/config@1.3.6
|
|
43
|
+
- @backstage/errors@1.2.7
|
|
44
|
+
- @backstage/types@1.2.2
|
|
45
|
+
- @backstage/plugin-events-node@0.4.20-next.0
|
|
46
|
+
- @backstage/plugin-permission-common@0.9.6
|
|
47
|
+
- @backstage/plugin-permission-node@0.10.11-next.0
|
|
48
|
+
|
|
49
|
+
## 3.1.4-next.0
|
|
4
50
|
|
|
5
51
|
### Patch Changes
|
|
6
52
|
|
|
7
|
-
-
|
|
53
|
+
- 4e39e63: Removed unused dependencies
|
|
8
54
|
- Updated dependencies
|
|
9
|
-
- @backstage/integration@1.
|
|
55
|
+
- @backstage/integration@1.21.0-next.0
|
|
56
|
+
- @backstage/plugin-catalog-node@2.1.0-next.0
|
|
57
|
+
- @backstage/backend-plugin-api@1.7.1-next.0
|
|
58
|
+
- @backstage/backend-openapi-utils@0.6.7-next.0
|
|
59
|
+
- @backstage/catalog-model@1.7.6
|
|
60
|
+
- @backstage/config@1.3.6
|
|
61
|
+
- @backstage/errors@1.2.7
|
|
62
|
+
- @backstage/types@1.2.2
|
|
63
|
+
- @backstage/plugin-events-node@0.4.20-next.0
|
|
64
|
+
- @backstage/plugin-permission-common@0.9.6
|
|
65
|
+
- @backstage/plugin-permission-node@0.10.11-next.0
|
|
66
|
+
- @backstage/plugin-scaffolder-common@1.7.7-next.0
|
|
67
|
+
- @backstage/plugin-scaffolder-node@0.12.6-next.0
|
|
10
68
|
|
|
11
69
|
## 3.1.3
|
|
12
70
|
|
|
@@ -32,6 +32,7 @@ var router = require('./service/router.cjs.js');
|
|
|
32
32
|
var loggerToWinstonLogger = require('./util/loggerToWinstonLogger.cjs.js');
|
|
33
33
|
var templating = require('./util/templating.cjs.js');
|
|
34
34
|
var alpha$1 = require('@backstage/backend-plugin-api/alpha');
|
|
35
|
+
var index = require('./actions/index.cjs.js');
|
|
35
36
|
|
|
36
37
|
const scaffolderPlugin = backendPluginApi.createBackendPlugin({
|
|
37
38
|
pluginId: "scaffolder",
|
|
@@ -98,7 +99,9 @@ const scaffolderPlugin = backendPluginApi.createBackendPlugin({
|
|
|
98
99
|
auditor: backendPluginApi.coreServices.auditor,
|
|
99
100
|
catalog: pluginCatalogNode.catalogServiceRef,
|
|
100
101
|
events: pluginEventsNode.eventsServiceRef,
|
|
101
|
-
actionsRegistry: alpha$1.actionsServiceRef
|
|
102
|
+
actionsRegistry: alpha$1.actionsServiceRef,
|
|
103
|
+
actionsRegistryService: alpha$1.actionsRegistryServiceRef,
|
|
104
|
+
scaffolderService: pluginScaffolderNode.scaffolderServiceRef
|
|
102
105
|
},
|
|
103
106
|
async init({
|
|
104
107
|
logger,
|
|
@@ -113,7 +116,9 @@ const scaffolderPlugin = backendPluginApi.createBackendPlugin({
|
|
|
113
116
|
permissions,
|
|
114
117
|
events,
|
|
115
118
|
auditor,
|
|
116
|
-
actionsRegistry
|
|
119
|
+
actionsRegistry,
|
|
120
|
+
actionsRegistryService,
|
|
121
|
+
scaffolderService
|
|
117
122
|
}) {
|
|
118
123
|
const log$1 = loggerToWinstonLogger.loggerToWinstonLogger(logger);
|
|
119
124
|
const integrations = integration.ScmIntegrations.fromConfig(config);
|
|
@@ -161,6 +166,11 @@ const scaffolderPlugin = backendPluginApi.createBackendPlugin({
|
|
|
161
166
|
log$1.info(
|
|
162
167
|
`Starting scaffolder with the following actions enabled ${actionIds}`
|
|
163
168
|
);
|
|
169
|
+
index.createScaffolderActions({
|
|
170
|
+
actionsRegistry: actionsRegistryService,
|
|
171
|
+
scaffolderService,
|
|
172
|
+
auth
|
|
173
|
+
});
|
|
164
174
|
const router$1 = await router.createRouter({
|
|
165
175
|
logger,
|
|
166
176
|
config,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScaffolderPlugin.cjs.js","sources":["../src/ScaffolderPlugin.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { catalogServiceRef } from '@backstage/plugin-catalog-node';\nimport { eventsServiceRef } from '@backstage/plugin-events-node';\nimport {\n scaffolderActionsExtensionPoint,\n TaskBroker,\n TemplateAction,\n} from '@backstage/plugin-scaffolder-node';\nimport {\n AutocompleteHandler,\n CreatedTemplateFilter,\n CreatedTemplateGlobal,\n createTemplateFilter,\n createTemplateGlobalFunction,\n createTemplateGlobalValue,\n scaffolderAutocompleteExtensionPoint,\n scaffolderTaskBrokerExtensionPoint,\n scaffolderTemplatingExtensionPoint,\n scaffolderWorkspaceProviderExtensionPoint,\n WorkspaceProvider,\n} from '@backstage/plugin-scaffolder-node/alpha';\nimport {\n createCatalogRegisterAction,\n createCatalogWriteAction,\n createDebugLogAction,\n createFetchCatalogEntityAction,\n createFetchPlainAction,\n createFetchPlainFileAction,\n createFetchTemplateAction,\n createFetchTemplateFileAction,\n createFilesystemDeleteAction,\n createFilesystemReadDirAction,\n createFilesystemRenameAction,\n createWaitAction,\n} from './scaffolder';\nimport { createRouter } from './service/router';\nimport { loggerToWinstonLogger } from './util/loggerToWinstonLogger';\nimport {\n convertFiltersToRecord,\n convertGlobalsToRecord,\n} from './util/templating';\nimport { actionsServiceRef } from '@backstage/backend-plugin-api/alpha';\n\n/**\n * Scaffolder plugin\n *\n * @public\n */\nexport const scaffolderPlugin = createBackendPlugin({\n pluginId: 'scaffolder',\n register(env) {\n const addedActions = new Array<TemplateAction<any, any>>();\n env.registerExtensionPoint(scaffolderActionsExtensionPoint, {\n addActions(...newActions: TemplateAction<any>[]) {\n addedActions.push(...newActions);\n },\n });\n\n let taskBroker: TaskBroker | undefined;\n env.registerExtensionPoint(scaffolderTaskBrokerExtensionPoint, {\n setTaskBroker(newTaskBroker) {\n if (taskBroker) {\n throw new Error('Task broker may only be set once');\n }\n taskBroker = newTaskBroker;\n },\n });\n\n const additionalTemplateFilters: CreatedTemplateFilter<any, any>[] = [];\n const additionalTemplateGlobals: CreatedTemplateGlobal[] = [];\n\n env.registerExtensionPoint(scaffolderTemplatingExtensionPoint, {\n addTemplateFilters(newFilters) {\n additionalTemplateFilters.push(\n ...(Array.isArray(newFilters)\n ? newFilters\n : Object.entries(newFilters).map(([id, filter]) =>\n createTemplateFilter({\n id,\n filter,\n }),\n )),\n );\n },\n addTemplateGlobals(newGlobals) {\n additionalTemplateGlobals.push(\n ...(Array.isArray(newGlobals)\n ? newGlobals\n : Object.entries(newGlobals).map(([id, global]) =>\n typeof global === 'function'\n ? createTemplateGlobalFunction({ id, fn: global })\n : createTemplateGlobalValue({ id, value: global }),\n )),\n );\n },\n });\n\n const autocompleteHandlers: Record<string, AutocompleteHandler> = {};\n env.registerExtensionPoint(scaffolderAutocompleteExtensionPoint, {\n addAutocompleteProvider(provider) {\n autocompleteHandlers[provider.id] = provider.handler;\n },\n });\n\n const additionalWorkspaceProviders: Record<string, WorkspaceProvider> = {};\n env.registerExtensionPoint(scaffolderWorkspaceProviderExtensionPoint, {\n addProviders(provider) {\n Object.assign(additionalWorkspaceProviders, provider);\n },\n });\n\n env.registerInit({\n deps: {\n logger: coreServices.logger,\n config: coreServices.rootConfig,\n lifecycle: coreServices.rootLifecycle,\n reader: coreServices.urlReader,\n permissions: coreServices.permissions,\n database: coreServices.database,\n auth: coreServices.auth,\n httpRouter: coreServices.httpRouter,\n httpAuth: coreServices.httpAuth,\n auditor: coreServices.auditor,\n catalog: catalogServiceRef,\n events: eventsServiceRef,\n actionsRegistry: actionsServiceRef,\n },\n async init({\n logger,\n config,\n lifecycle,\n reader,\n database,\n auth,\n httpRouter,\n httpAuth,\n catalog,\n permissions,\n events,\n auditor,\n actionsRegistry,\n }) {\n const log = loggerToWinstonLogger(logger);\n const integrations = ScmIntegrations.fromConfig(config);\n\n const templateExtensions = {\n additionalTemplateFilters: convertFiltersToRecord(\n additionalTemplateFilters,\n ),\n additionalTemplateGlobals: convertGlobalsToRecord(\n additionalTemplateGlobals,\n ),\n };\n const actions = [\n // actions provided from other modules\n ...addedActions,\n\n // built-in actions for the scaffolder\n createFetchPlainAction({\n reader,\n integrations,\n }),\n createFetchPlainFileAction({\n reader,\n integrations,\n }),\n createFetchTemplateAction({\n integrations,\n reader,\n ...templateExtensions,\n }),\n createFetchTemplateFileAction({\n integrations,\n reader,\n ...templateExtensions,\n }),\n createDebugLogAction(),\n createWaitAction(),\n // todo(blam): maybe these should be a -catalog module?\n createCatalogRegisterAction({ catalog, integrations }),\n createFetchCatalogEntityAction({ catalog }),\n createCatalogWriteAction(),\n createFilesystemDeleteAction(),\n createFilesystemRenameAction(),\n createFilesystemReadDirAction(),\n ];\n\n const actionIds = actions.map(action => action.id).join(', ');\n\n log.info(\n `Starting scaffolder with the following actions enabled ${actionIds}`,\n );\n\n const router = await createRouter({\n logger,\n config,\n database,\n catalog,\n lifecycle,\n actions,\n taskBroker,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n auth,\n httpAuth,\n permissions,\n autocompleteHandlers,\n additionalWorkspaceProviders,\n events,\n auditor,\n actionsRegistry,\n });\n httpRouter.use(router);\n },\n });\n },\n});\n"],"names":["createBackendPlugin","scaffolderActionsExtensionPoint","scaffolderTaskBrokerExtensionPoint","scaffolderTemplatingExtensionPoint","createTemplateFilter","createTemplateGlobalFunction","createTemplateGlobalValue","scaffolderAutocompleteExtensionPoint","scaffolderWorkspaceProviderExtensionPoint","coreServices","catalogServiceRef","eventsServiceRef","actionsServiceRef","log","loggerToWinstonLogger","ScmIntegrations","convertFiltersToRecord","convertGlobalsToRecord","createFetchPlainAction","createFetchPlainFileAction","createFetchTemplateAction","createFetchTemplateFileAction","createDebugLogAction","createWaitAction","createCatalogRegisterAction","createFetchCatalogEntityAction","createCatalogWriteAction","createFilesystemDeleteAction","createFilesystemRenameAction","createFilesystemReadDirAction","router","createRouter"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ScaffolderPlugin.cjs.js","sources":["../src/ScaffolderPlugin.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { catalogServiceRef } from '@backstage/plugin-catalog-node';\nimport { eventsServiceRef } from '@backstage/plugin-events-node';\nimport {\n scaffolderActionsExtensionPoint,\n scaffolderServiceRef,\n TaskBroker,\n TemplateAction,\n} from '@backstage/plugin-scaffolder-node';\nimport {\n AutocompleteHandler,\n CreatedTemplateFilter,\n CreatedTemplateGlobal,\n createTemplateFilter,\n createTemplateGlobalFunction,\n createTemplateGlobalValue,\n scaffolderAutocompleteExtensionPoint,\n scaffolderTaskBrokerExtensionPoint,\n scaffolderTemplatingExtensionPoint,\n scaffolderWorkspaceProviderExtensionPoint,\n WorkspaceProvider,\n} from '@backstage/plugin-scaffolder-node/alpha';\nimport {\n createCatalogRegisterAction,\n createCatalogWriteAction,\n createDebugLogAction,\n createFetchCatalogEntityAction,\n createFetchPlainAction,\n createFetchPlainFileAction,\n createFetchTemplateAction,\n createFetchTemplateFileAction,\n createFilesystemDeleteAction,\n createFilesystemReadDirAction,\n createFilesystemRenameAction,\n createWaitAction,\n} from './scaffolder';\nimport { createRouter } from './service/router';\nimport { loggerToWinstonLogger } from './util/loggerToWinstonLogger';\nimport {\n convertFiltersToRecord,\n convertGlobalsToRecord,\n} from './util/templating';\nimport {\n actionsServiceRef,\n actionsRegistryServiceRef,\n} from '@backstage/backend-plugin-api/alpha';\nimport { createScaffolderActions } from './actions';\n\n/**\n * Scaffolder plugin\n *\n * @public\n */\nexport const scaffolderPlugin = createBackendPlugin({\n pluginId: 'scaffolder',\n register(env) {\n const addedActions = new Array<TemplateAction<any, any>>();\n env.registerExtensionPoint(scaffolderActionsExtensionPoint, {\n addActions(...newActions: TemplateAction<any>[]) {\n addedActions.push(...newActions);\n },\n });\n\n let taskBroker: TaskBroker | undefined;\n env.registerExtensionPoint(scaffolderTaskBrokerExtensionPoint, {\n setTaskBroker(newTaskBroker) {\n if (taskBroker) {\n throw new Error('Task broker may only be set once');\n }\n taskBroker = newTaskBroker;\n },\n });\n\n const additionalTemplateFilters: CreatedTemplateFilter<any, any>[] = [];\n const additionalTemplateGlobals: CreatedTemplateGlobal[] = [];\n\n env.registerExtensionPoint(scaffolderTemplatingExtensionPoint, {\n addTemplateFilters(newFilters) {\n additionalTemplateFilters.push(\n ...(Array.isArray(newFilters)\n ? newFilters\n : Object.entries(newFilters).map(([id, filter]) =>\n createTemplateFilter({\n id,\n filter,\n }),\n )),\n );\n },\n addTemplateGlobals(newGlobals) {\n additionalTemplateGlobals.push(\n ...(Array.isArray(newGlobals)\n ? newGlobals\n : Object.entries(newGlobals).map(([id, global]) =>\n typeof global === 'function'\n ? createTemplateGlobalFunction({ id, fn: global })\n : createTemplateGlobalValue({ id, value: global }),\n )),\n );\n },\n });\n\n const autocompleteHandlers: Record<string, AutocompleteHandler> = {};\n env.registerExtensionPoint(scaffolderAutocompleteExtensionPoint, {\n addAutocompleteProvider(provider) {\n autocompleteHandlers[provider.id] = provider.handler;\n },\n });\n\n const additionalWorkspaceProviders: Record<string, WorkspaceProvider> = {};\n env.registerExtensionPoint(scaffolderWorkspaceProviderExtensionPoint, {\n addProviders(provider) {\n Object.assign(additionalWorkspaceProviders, provider);\n },\n });\n\n env.registerInit({\n deps: {\n logger: coreServices.logger,\n config: coreServices.rootConfig,\n lifecycle: coreServices.rootLifecycle,\n reader: coreServices.urlReader,\n permissions: coreServices.permissions,\n database: coreServices.database,\n auth: coreServices.auth,\n httpRouter: coreServices.httpRouter,\n httpAuth: coreServices.httpAuth,\n auditor: coreServices.auditor,\n catalog: catalogServiceRef,\n events: eventsServiceRef,\n actionsRegistry: actionsServiceRef,\n actionsRegistryService: actionsRegistryServiceRef,\n scaffolderService: scaffolderServiceRef,\n },\n async init({\n logger,\n config,\n lifecycle,\n reader,\n database,\n auth,\n httpRouter,\n httpAuth,\n catalog,\n permissions,\n events,\n auditor,\n actionsRegistry,\n actionsRegistryService,\n scaffolderService,\n }) {\n const log = loggerToWinstonLogger(logger);\n const integrations = ScmIntegrations.fromConfig(config);\n\n const templateExtensions = {\n additionalTemplateFilters: convertFiltersToRecord(\n additionalTemplateFilters,\n ),\n additionalTemplateGlobals: convertGlobalsToRecord(\n additionalTemplateGlobals,\n ),\n };\n const actions = [\n // actions provided from other modules\n ...addedActions,\n\n // built-in actions for the scaffolder\n createFetchPlainAction({\n reader,\n integrations,\n }),\n createFetchPlainFileAction({\n reader,\n integrations,\n }),\n createFetchTemplateAction({\n integrations,\n reader,\n ...templateExtensions,\n }),\n createFetchTemplateFileAction({\n integrations,\n reader,\n ...templateExtensions,\n }),\n createDebugLogAction(),\n createWaitAction(),\n // todo(blam): maybe these should be a -catalog module?\n createCatalogRegisterAction({ catalog, integrations }),\n createFetchCatalogEntityAction({ catalog }),\n createCatalogWriteAction(),\n createFilesystemDeleteAction(),\n createFilesystemRenameAction(),\n createFilesystemReadDirAction(),\n ];\n\n const actionIds = actions.map(action => action.id).join(', ');\n\n log.info(\n `Starting scaffolder with the following actions enabled ${actionIds}`,\n );\n\n createScaffolderActions({\n actionsRegistry: actionsRegistryService,\n scaffolderService,\n auth,\n });\n\n const router = await createRouter({\n logger,\n config,\n database,\n catalog,\n lifecycle,\n actions,\n taskBroker,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n auth,\n httpAuth,\n permissions,\n autocompleteHandlers,\n additionalWorkspaceProviders,\n events,\n auditor,\n actionsRegistry,\n });\n httpRouter.use(router);\n },\n });\n },\n});\n"],"names":["createBackendPlugin","scaffolderActionsExtensionPoint","scaffolderTaskBrokerExtensionPoint","scaffolderTemplatingExtensionPoint","createTemplateFilter","createTemplateGlobalFunction","createTemplateGlobalValue","scaffolderAutocompleteExtensionPoint","scaffolderWorkspaceProviderExtensionPoint","coreServices","catalogServiceRef","eventsServiceRef","actionsServiceRef","actionsRegistryServiceRef","scaffolderServiceRef","log","loggerToWinstonLogger","ScmIntegrations","convertFiltersToRecord","convertGlobalsToRecord","createFetchPlainAction","createFetchPlainFileAction","createFetchTemplateAction","createFetchTemplateFileAction","createDebugLogAction","createWaitAction","createCatalogRegisterAction","createFetchCatalogEntityAction","createCatalogWriteAction","createFilesystemDeleteAction","createFilesystemRenameAction","createFilesystemReadDirAction","createScaffolderActions","router","createRouter"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyEO,MAAM,mBAAmBA,oCAAA,CAAoB;AAAA,EAClD,QAAA,EAAU,YAAA;AAAA,EACV,SAAS,GAAA,EAAK;AACZ,IAAA,MAAM,YAAA,GAAe,IAAI,KAAA,EAAgC;AACzD,IAAA,GAAA,CAAI,uBAAuBC,oDAAA,EAAiC;AAAA,MAC1D,cAAc,UAAA,EAAmC;AAC/C,QAAA,YAAA,CAAa,IAAA,CAAK,GAAG,UAAU,CAAA;AAAA,MACjC;AAAA,KACD,CAAA;AAED,IAAA,IAAI,UAAA;AACJ,IAAA,GAAA,CAAI,uBAAuBC,wCAAA,EAAoC;AAAA,MAC7D,cAAc,aAAA,EAAe;AAC3B,QAAA,IAAI,UAAA,EAAY;AACd,UAAA,MAAM,IAAI,MAAM,kCAAkC,CAAA;AAAA,QACpD;AACA,QAAA,UAAA,GAAa,aAAA;AAAA,MACf;AAAA,KACD,CAAA;AAED,IAAA,MAAM,4BAA+D,EAAC;AACtE,IAAA,MAAM,4BAAqD,EAAC;AAE5D,IAAA,GAAA,CAAI,uBAAuBC,wCAAA,EAAoC;AAAA,MAC7D,mBAAmB,UAAA,EAAY;AAC7B,QAAA,yBAAA,CAA0B,IAAA;AAAA,UACxB,GAAI,MAAM,OAAA,CAAQ,UAAU,IACxB,UAAA,GACA,MAAA,CAAO,OAAA,CAAQ,UAAU,CAAA,CAAE,GAAA;AAAA,YAAI,CAAC,CAAC,EAAA,EAAI,MAAM,MACzCC,0BAAA,CAAqB;AAAA,cACnB,EAAA;AAAA,cACA;AAAA,aACD;AAAA;AACH,SACN;AAAA,MACF,CAAA;AAAA,MACA,mBAAmB,UAAA,EAAY;AAC7B,QAAA,yBAAA,CAA0B,IAAA;AAAA,UACxB,GAAI,MAAM,OAAA,CAAQ,UAAU,IACxB,UAAA,GACA,MAAA,CAAO,OAAA,CAAQ,UAAU,CAAA,CAAE,GAAA;AAAA,YAAI,CAAC,CAAC,EAAA,EAAI,MAAM,MACzC,OAAO,MAAA,KAAW,aACdC,kCAAA,CAA6B,EAAE,IAAI,EAAA,EAAI,MAAA,EAAQ,CAAA,GAC/CC,+BAAA,CAA0B,EAAE,EAAA,EAAI,KAAA,EAAO,QAAQ;AAAA;AACrD,SACN;AAAA,MACF;AAAA,KACD,CAAA;AAED,IAAA,MAAM,uBAA4D,EAAC;AACnE,IAAA,GAAA,CAAI,uBAAuBC,0CAAA,EAAsC;AAAA,MAC/D,wBAAwB,QAAA,EAAU;AAChC,QAAA,oBAAA,CAAqB,QAAA,CAAS,EAAE,CAAA,GAAI,QAAA,CAAS,OAAA;AAAA,MAC/C;AAAA,KACD,CAAA;AAED,IAAA,MAAM,+BAAkE,EAAC;AACzE,IAAA,GAAA,CAAI,uBAAuBC,+CAAA,EAA2C;AAAA,MACpE,aAAa,QAAA,EAAU;AACrB,QAAA,MAAA,CAAO,MAAA,CAAO,8BAA8B,QAAQ,CAAA;AAAA,MACtD;AAAA,KACD,CAAA;AAED,IAAA,GAAA,CAAI,YAAA,CAAa;AAAA,MACf,IAAA,EAAM;AAAA,QACJ,QAAQC,6BAAA,CAAa,MAAA;AAAA,QACrB,QAAQA,6BAAA,CAAa,UAAA;AAAA,QACrB,WAAWA,6BAAA,CAAa,aAAA;AAAA,QACxB,QAAQA,6BAAA,CAAa,SAAA;AAAA,QACrB,aAAaA,6BAAA,CAAa,WAAA;AAAA,QAC1B,UAAUA,6BAAA,CAAa,QAAA;AAAA,QACvB,MAAMA,6BAAA,CAAa,IAAA;AAAA,QACnB,YAAYA,6BAAA,CAAa,UAAA;AAAA,QACzB,UAAUA,6BAAA,CAAa,QAAA;AAAA,QACvB,SAASA,6BAAA,CAAa,OAAA;AAAA,QACtB,OAAA,EAASC,mCAAA;AAAA,QACT,MAAA,EAAQC,iCAAA;AAAA,QACR,eAAA,EAAiBC,yBAAA;AAAA,QACjB,sBAAA,EAAwBC,iCAAA;AAAA,QACxB,iBAAA,EAAmBC;AAAA,OACrB;AAAA,MACA,MAAM,IAAA,CAAK;AAAA,QACT,MAAA;AAAA,QACA,MAAA;AAAA,QACA,SAAA;AAAA,QACA,MAAA;AAAA,QACA,QAAA;AAAA,QACA,IAAA;AAAA,QACA,UAAA;AAAA,QACA,QAAA;AAAA,QACA,OAAA;AAAA,QACA,WAAA;AAAA,QACA,MAAA;AAAA,QACA,OAAA;AAAA,QACA,eAAA;AAAA,QACA,sBAAA;AAAA,QACA;AAAA,OACF,EAAG;AACD,QAAA,MAAMC,KAAA,GAAMC,4CAAsB,MAAM,CAAA;AACxC,QAAA,MAAM,YAAA,GAAeC,2BAAA,CAAgB,UAAA,CAAW,MAAM,CAAA;AAEtD,QAAA,MAAM,kBAAA,GAAqB;AAAA,UACzB,yBAAA,EAA2BC,iCAAA;AAAA,YACzB;AAAA,WACF;AAAA,UACA,yBAAA,EAA2BC,iCAAA;AAAA,YACzB;AAAA;AACF,SACF;AACA,QAAA,MAAM,OAAA,GAAU;AAAA;AAAA,UAEd,GAAG,YAAA;AAAA;AAAA,UAGHC,4BAAA,CAAuB;AAAA,YACrB,MAAA;AAAA,YACA;AAAA,WACD,CAAA;AAAA,UACDC,oCAAA,CAA2B;AAAA,YACzB,MAAA;AAAA,YACA;AAAA,WACD,CAAA;AAAA,UACDC,kCAAA,CAA0B;AAAA,YACxB,YAAA;AAAA,YACA,MAAA;AAAA,YACA,GAAG;AAAA,WACJ,CAAA;AAAA,UACDC,0CAAA,CAA8B;AAAA,YAC5B,YAAA;AAAA,YACA,MAAA;AAAA,YACA,GAAG;AAAA,WACJ,CAAA;AAAA,UACDC,wBAAA,EAAqB;AAAA,UACrBC,qBAAA,EAAiB;AAAA;AAAA,UAEjBC,oCAAA,CAA4B,EAAE,OAAA,EAAS,YAAA,EAAc,CAAA;AAAA,UACrDC,oCAAA,CAA+B,EAAE,OAAA,EAAS,CAAA;AAAA,UAC1CC,8BAAA,EAAyB;AAAA,UACzBC,oCAAA,EAA6B;AAAA,UAC7BC,mCAAA,EAA6B;AAAA,UAC7BC,kCAAA;AAA8B,SAChC;AAEA,QAAA,MAAM,SAAA,GAAY,QAAQ,GAAA,CAAI,CAAA,MAAA,KAAU,OAAO,EAAE,CAAA,CAAE,KAAK,IAAI,CAAA;AAE5D,QAAAhB,KAAA,CAAI,IAAA;AAAA,UACF,0DAA0D,SAAS,CAAA;AAAA,SACrE;AAEA,QAAAiB,6BAAA,CAAwB;AAAA,UACtB,eAAA,EAAiB,sBAAA;AAAA,UACjB,iBAAA;AAAA,UACA;AAAA,SACD,CAAA;AAED,QAAA,MAAMC,QAAA,GAAS,MAAMC,mBAAA,CAAa;AAAA,UAChC,MAAA;AAAA,UACA,MAAA;AAAA,UACA,QAAA;AAAA,UACA,OAAA;AAAA,UACA,SAAA;AAAA,UACA,OAAA;AAAA,UACA,UAAA;AAAA,UACA,yBAAA;AAAA,UACA,yBAAA;AAAA,UACA,IAAA;AAAA,UACA,QAAA;AAAA,UACA,WAAA;AAAA,UACA,oBAAA;AAAA,UACA,4BAAA;AAAA,UACA,MAAA;AAAA,UACA,OAAA;AAAA,UACA;AAAA,SACD,CAAA;AACD,QAAA,UAAA,CAAW,IAAID,QAAM,CAAA;AAAA,MACvB;AAAA,KACD,CAAA;AAAA,EACH;AACF,CAAC;;;;"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var yaml = require('yaml');
|
|
4
|
+
|
|
5
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
6
|
+
|
|
7
|
+
var yaml__default = /*#__PURE__*/_interopDefaultCompat(yaml);
|
|
8
|
+
|
|
9
|
+
const MAX_CONTENT_SIZE = 64 * 1024;
|
|
10
|
+
function base64EncodeContent(content) {
|
|
11
|
+
if (content.length > MAX_CONTENT_SIZE) {
|
|
12
|
+
return Buffer.from("<file too large>", "utf8").toString("base64");
|
|
13
|
+
}
|
|
14
|
+
return Buffer.from(content, "utf8").toString("base64");
|
|
15
|
+
}
|
|
16
|
+
const createDryRunTemplateAction = ({
|
|
17
|
+
actionsRegistry,
|
|
18
|
+
scaffolderService
|
|
19
|
+
}) => {
|
|
20
|
+
actionsRegistry.register({
|
|
21
|
+
name: "dry-run-template",
|
|
22
|
+
title: "Dry Run Scaffolder Template",
|
|
23
|
+
attributes: {
|
|
24
|
+
destructive: false,
|
|
25
|
+
readOnly: true,
|
|
26
|
+
idempotent: true
|
|
27
|
+
},
|
|
28
|
+
description: "Dry-runs a scaffolder template to validate it without making changes. Returns success with execution logs, or errors for validation failures.",
|
|
29
|
+
schema: {
|
|
30
|
+
input: (z) => z.object({
|
|
31
|
+
templateYaml: z.string().describe(
|
|
32
|
+
"The YAML content of the scaffolder template to validate"
|
|
33
|
+
),
|
|
34
|
+
values: z.record(z.unknown()).optional().describe("Input values for template parameters"),
|
|
35
|
+
files: z.array(
|
|
36
|
+
z.object({
|
|
37
|
+
path: z.string().describe("File path relative to template root"),
|
|
38
|
+
content: z.string().describe("File content")
|
|
39
|
+
})
|
|
40
|
+
).optional().describe("Files required for running the template")
|
|
41
|
+
}),
|
|
42
|
+
output: (z) => z.object({
|
|
43
|
+
valid: z.boolean().describe("Whether the template is valid"),
|
|
44
|
+
message: z.string().describe("Success message or validation error details"),
|
|
45
|
+
errors: z.array(z.string()).optional().describe("List of validation errors"),
|
|
46
|
+
log: z.array(
|
|
47
|
+
z.object({
|
|
48
|
+
message: z.string(),
|
|
49
|
+
stepId: z.string().optional(),
|
|
50
|
+
status: z.string().optional()
|
|
51
|
+
})
|
|
52
|
+
).optional().describe("Execution log from dry-run"),
|
|
53
|
+
output: z.record(z.unknown()).optional().describe("Template output values"),
|
|
54
|
+
steps: z.array(
|
|
55
|
+
z.object({
|
|
56
|
+
id: z.string(),
|
|
57
|
+
name: z.string(),
|
|
58
|
+
action: z.string()
|
|
59
|
+
})
|
|
60
|
+
).optional().describe("Parsed template steps")
|
|
61
|
+
})
|
|
62
|
+
},
|
|
63
|
+
action: async ({ input, credentials }) => {
|
|
64
|
+
const { templateYaml, values = {}, files = [] } = input;
|
|
65
|
+
let template;
|
|
66
|
+
try {
|
|
67
|
+
template = yaml__default.default.parse(templateYaml);
|
|
68
|
+
} catch (parseError) {
|
|
69
|
+
const yamlError = parseError;
|
|
70
|
+
return {
|
|
71
|
+
output: {
|
|
72
|
+
valid: false,
|
|
73
|
+
message: "Failed to parse YAML template",
|
|
74
|
+
errors: [
|
|
75
|
+
`YAML parsing error: ${yamlError.message}`,
|
|
76
|
+
yamlError.linePos ? `At line ${yamlError.linePos[0].line}, column ${yamlError.linePos[0].col}` : ""
|
|
77
|
+
].filter(Boolean)
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
const result = await scaffolderService.dryRun(
|
|
82
|
+
{
|
|
83
|
+
template,
|
|
84
|
+
values,
|
|
85
|
+
directoryContents: files.map((file) => ({
|
|
86
|
+
path: file.path,
|
|
87
|
+
base64Content: base64EncodeContent(file.content)
|
|
88
|
+
}))
|
|
89
|
+
},
|
|
90
|
+
{ credentials }
|
|
91
|
+
);
|
|
92
|
+
return {
|
|
93
|
+
output: {
|
|
94
|
+
valid: true,
|
|
95
|
+
message: "Template validation successful",
|
|
96
|
+
log: result.log?.map((entry) => ({
|
|
97
|
+
message: entry.body.message,
|
|
98
|
+
stepId: entry.body.stepId,
|
|
99
|
+
status: entry.body.status
|
|
100
|
+
})),
|
|
101
|
+
output: result.output,
|
|
102
|
+
steps: result.steps
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
exports.createDryRunTemplateAction = createDryRunTemplateAction;
|
|
110
|
+
//# sourceMappingURL=createDryRunTemplateAction.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createDryRunTemplateAction.cjs.js","sources":["../../src/actions/createDryRunTemplateAction.ts"],"sourcesContent":["/*\n * Copyright 2026 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { ActionsRegistryService } from '@backstage/backend-plugin-api/alpha';\nimport { ScaffolderService } from '@backstage/plugin-scaffolder-node';\nimport { JsonObject } from '@backstage/types';\nimport yaml from 'yaml';\n\nconst MAX_CONTENT_SIZE = 64 * 1024;\n\nfunction base64EncodeContent(content: string): string {\n if (content.length > MAX_CONTENT_SIZE) {\n return Buffer.from('<file too large>', 'utf8').toString('base64');\n }\n return Buffer.from(content, 'utf8').toString('base64');\n}\n\nexport const createDryRunTemplateAction = ({\n actionsRegistry,\n scaffolderService,\n}: {\n actionsRegistry: ActionsRegistryService;\n scaffolderService: ScaffolderService;\n}) => {\n actionsRegistry.register({\n name: 'dry-run-template',\n title: 'Dry Run Scaffolder Template',\n attributes: {\n destructive: false,\n readOnly: true,\n idempotent: true,\n },\n description:\n 'Dry-runs a scaffolder template to validate it without making changes. Returns success with execution logs, or errors for validation failures.',\n schema: {\n input: z =>\n z.object({\n templateYaml: z\n .string()\n .describe(\n 'The YAML content of the scaffolder template to validate',\n ),\n values: z\n .record(z.unknown())\n .optional()\n .describe('Input values for template parameters'),\n files: z\n .array(\n z.object({\n path: z\n .string()\n .describe('File path relative to template root'),\n content: z.string().describe('File content'),\n }),\n )\n .optional()\n .describe('Files required for running the template'),\n }),\n output: z =>\n z.object({\n valid: z.boolean().describe('Whether the template is valid'),\n message: z\n .string()\n .describe('Success message or validation error details'),\n errors: z\n .array(z.string())\n .optional()\n .describe('List of validation errors'),\n log: z\n .array(\n z.object({\n message: z.string(),\n stepId: z.string().optional(),\n status: z.string().optional(),\n }),\n )\n .optional()\n .describe('Execution log from dry-run'),\n output: z\n .record(z.unknown())\n .optional()\n .describe('Template output values'),\n steps: z\n .array(\n z.object({\n id: z.string(),\n name: z.string(),\n action: z.string(),\n }),\n )\n .optional()\n .describe('Parsed template steps'),\n }),\n },\n action: async ({ input, credentials }) => {\n const { templateYaml, values = {}, files = [] } = input;\n\n let template;\n try {\n template = yaml.parse(templateYaml);\n } catch (parseError) {\n const yamlError = parseError as yaml.YAMLParseError;\n return {\n output: {\n valid: false,\n message: 'Failed to parse YAML template',\n errors: [\n `YAML parsing error: ${yamlError.message}`,\n yamlError.linePos\n ? `At line ${yamlError.linePos[0].line}, column ${yamlError.linePos[0].col}`\n : '',\n ].filter(Boolean),\n },\n };\n }\n\n const result = await scaffolderService.dryRun(\n {\n template,\n values: values as JsonObject,\n directoryContents: files.map(file => ({\n path: file.path,\n base64Content: base64EncodeContent(file.content),\n })),\n },\n { credentials },\n );\n\n return {\n output: {\n valid: true,\n message: 'Template validation successful',\n log: result.log?.map(entry => ({\n message: entry.body.message,\n stepId: entry.body.stepId,\n status: entry.body.status,\n })),\n output: result.output,\n steps: result.steps,\n },\n };\n },\n });\n};\n"],"names":["yaml"],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const createListScaffolderActionsAction = ({
|
|
4
|
+
actionsRegistry,
|
|
5
|
+
scaffolderService
|
|
6
|
+
}) => {
|
|
7
|
+
actionsRegistry.register({
|
|
8
|
+
name: "list-scaffolder-actions",
|
|
9
|
+
title: "List Scaffolder Actions",
|
|
10
|
+
attributes: {
|
|
11
|
+
destructive: false,
|
|
12
|
+
readOnly: true,
|
|
13
|
+
idempotent: true
|
|
14
|
+
},
|
|
15
|
+
description: `Lists all installed Scaffolder actions.
|
|
16
|
+
Each action includes:
|
|
17
|
+
- id: The action identifier
|
|
18
|
+
- description: What the action does
|
|
19
|
+
- schema: Input and output JSON schemas
|
|
20
|
+
- examples: Usage examples when available`,
|
|
21
|
+
schema: {
|
|
22
|
+
input: (z) => z.object({}).describe("No input is required"),
|
|
23
|
+
output: (z) => z.object({
|
|
24
|
+
actions: z.array(
|
|
25
|
+
z.object({
|
|
26
|
+
id: z.string(),
|
|
27
|
+
description: z.string(),
|
|
28
|
+
schema: z.object({
|
|
29
|
+
input: z.object({}).passthrough().describe("JSON Schema for input of Action"),
|
|
30
|
+
output: z.object({}).passthrough().describe("JSON Schema for output of Action")
|
|
31
|
+
}),
|
|
32
|
+
examples: z.array(z.any()).optional()
|
|
33
|
+
})
|
|
34
|
+
)
|
|
35
|
+
})
|
|
36
|
+
},
|
|
37
|
+
action: async ({ credentials }) => {
|
|
38
|
+
const actions = await scaffolderService.listActions(void 0, {
|
|
39
|
+
credentials
|
|
40
|
+
});
|
|
41
|
+
const scaffolderActions = actions.map((action) => ({
|
|
42
|
+
id: action.id,
|
|
43
|
+
description: action.description ?? "",
|
|
44
|
+
schema: {
|
|
45
|
+
input: { ...action.schema?.input ?? {} },
|
|
46
|
+
output: { ...action.schema?.output ?? {} }
|
|
47
|
+
},
|
|
48
|
+
examples: action.examples ?? []
|
|
49
|
+
}));
|
|
50
|
+
return {
|
|
51
|
+
output: {
|
|
52
|
+
actions: scaffolderActions.sort((a, b) => a.id.localeCompare(b.id))
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
exports.createListScaffolderActionsAction = createListScaffolderActionsAction;
|
|
60
|
+
//# sourceMappingURL=createListScaffolderActionsAction.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createListScaffolderActionsAction.cjs.js","sources":["../../src/actions/createListScaffolderActionsAction.ts"],"sourcesContent":["/*\n * Copyright 2026 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { ActionsRegistryService } from '@backstage/backend-plugin-api/alpha';\nimport { ScaffolderService } from '@backstage/plugin-scaffolder-node';\n\nexport const createListScaffolderActionsAction = ({\n actionsRegistry,\n scaffolderService,\n}: {\n actionsRegistry: ActionsRegistryService;\n scaffolderService: ScaffolderService;\n}) => {\n actionsRegistry.register({\n name: 'list-scaffolder-actions',\n title: 'List Scaffolder Actions',\n attributes: {\n destructive: false,\n readOnly: true,\n idempotent: true,\n },\n description: `Lists all installed Scaffolder actions.\nEach action includes:\n- id: The action identifier\n- description: What the action does\n- schema: Input and output JSON schemas\n- examples: Usage examples when available`,\n schema: {\n input: z => z.object({}).describe('No input is required'),\n output: z =>\n z.object({\n actions: z.array(\n z.object({\n id: z.string(),\n description: z.string(),\n schema: z.object({\n input: z\n .object({})\n .passthrough()\n .describe('JSON Schema for input of Action'),\n output: z\n .object({})\n .passthrough()\n .describe('JSON Schema for output of Action'),\n }),\n examples: z.array(z.any()).optional(),\n }),\n ),\n }),\n },\n action: async ({ credentials }) => {\n const actions = await scaffolderService.listActions(undefined, {\n credentials,\n });\n const scaffolderActions = actions.map(action => ({\n id: action.id,\n description: action.description ?? '',\n schema: {\n input: { ...(action.schema?.input ?? {}) },\n output: { ...(action.schema?.output ?? {}) },\n },\n examples: action.examples ?? [],\n }));\n return {\n output: {\n actions: scaffolderActions.sort((a, b) => a.id.localeCompare(b.id)),\n },\n };\n },\n });\n};\n"],"names":[],"mappings":";;AAkBO,MAAM,oCAAoC,CAAC;AAAA,EAChD,eAAA;AAAA,EACA;AACF,CAAA,KAGM;AACJ,EAAA,eAAA,CAAgB,QAAA,CAAS;AAAA,IACvB,IAAA,EAAM,yBAAA;AAAA,IACN,KAAA,EAAO,yBAAA;AAAA,IACP,UAAA,EAAY;AAAA,MACV,WAAA,EAAa,KAAA;AAAA,MACb,QAAA,EAAU,IAAA;AAAA,MACV,UAAA,EAAY;AAAA,KACd;AAAA,IACA,WAAA,EAAa,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yCAAA,CAAA;AAAA,IAMb,MAAA,EAAQ;AAAA,MACN,KAAA,EAAO,OAAK,CAAA,CAAE,MAAA,CAAO,EAAE,CAAA,CAAE,SAAS,sBAAsB,CAAA;AAAA,MACxD,MAAA,EAAQ,CAAA,CAAA,KACN,CAAA,CAAE,MAAA,CAAO;AAAA,QACP,SAAS,CAAA,CAAE,KAAA;AAAA,UACT,EAAE,MAAA,CAAO;AAAA,YACP,EAAA,EAAI,EAAE,MAAA,EAAO;AAAA,YACb,WAAA,EAAa,EAAE,MAAA,EAAO;AAAA,YACtB,MAAA,EAAQ,EAAE,MAAA,CAAO;AAAA,cACf,KAAA,EAAO,EACJ,MAAA,CAAO,EAAE,CAAA,CACT,WAAA,EAAY,CACZ,QAAA,CAAS,iCAAiC,CAAA;AAAA,cAC7C,MAAA,EAAQ,EACL,MAAA,CAAO,EAAE,CAAA,CACT,WAAA,EAAY,CACZ,QAAA,CAAS,kCAAkC;AAAA,aAC/C,CAAA;AAAA,YACD,UAAU,CAAA,CAAE,KAAA,CAAM,EAAE,GAAA,EAAK,EAAE,QAAA;AAAS,WACrC;AAAA;AACH,OACD;AAAA,KACL;AAAA,IACA,MAAA,EAAQ,OAAO,EAAE,WAAA,EAAY,KAAM;AACjC,MAAA,MAAM,OAAA,GAAU,MAAM,iBAAA,CAAkB,WAAA,CAAY,MAAA,EAAW;AAAA,QAC7D;AAAA,OACD,CAAA;AACD,MAAA,MAAM,iBAAA,GAAoB,OAAA,CAAQ,GAAA,CAAI,CAAA,MAAA,MAAW;AAAA,QAC/C,IAAI,MAAA,CAAO,EAAA;AAAA,QACX,WAAA,EAAa,OAAO,WAAA,IAAe,EAAA;AAAA,QACnC,MAAA,EAAQ;AAAA,UACN,OAAO,EAAE,GAAI,OAAO,MAAA,EAAQ,KAAA,IAAS,EAAC,EAAG;AAAA,UACzC,QAAQ,EAAE,GAAI,OAAO,MAAA,EAAQ,MAAA,IAAU,EAAC;AAAG,SAC7C;AAAA,QACA,QAAA,EAAU,MAAA,CAAO,QAAA,IAAY;AAAC,OAChC,CAAE,CAAA;AACF,MAAA,OAAO;AAAA,QACL,MAAA,EAAQ;AAAA,UACN,OAAA,EAAS,iBAAA,CAAkB,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,CAAE,EAAA,CAAG,aAAA,CAAc,CAAA,CAAE,EAAE,CAAC;AAAA;AACpE,OACF;AAAA,IACF;AAAA,GACD,CAAA;AACH;;;;"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var listScaffolderTasksAction = require('./listScaffolderTasksAction.cjs.js');
|
|
4
|
+
var createDryRunTemplateAction = require('./createDryRunTemplateAction.cjs.js');
|
|
5
|
+
var createListScaffolderActionsAction = require('./createListScaffolderActionsAction.cjs.js');
|
|
6
|
+
|
|
7
|
+
const createScaffolderActions = (options) => {
|
|
8
|
+
listScaffolderTasksAction.createListScaffolderTasksAction({
|
|
9
|
+
actionsRegistry: options.actionsRegistry,
|
|
10
|
+
auth: options.auth,
|
|
11
|
+
scaffolderService: options.scaffolderService
|
|
12
|
+
});
|
|
13
|
+
createDryRunTemplateAction.createDryRunTemplateAction(options);
|
|
14
|
+
createListScaffolderActionsAction.createListScaffolderActionsAction(options);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
exports.createScaffolderActions = createScaffolderActions;
|
|
18
|
+
//# sourceMappingURL=index.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":["../../src/actions/index.ts"],"sourcesContent":["/*\n * Copyright 2026 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { ActionsRegistryService } from '@backstage/backend-plugin-api/alpha';\nimport { AuthService } from '@backstage/backend-plugin-api';\nimport { createListScaffolderTasksAction } from './listScaffolderTasksAction';\nimport { ScaffolderService } from '@backstage/plugin-scaffolder-node';\nimport { createDryRunTemplateAction } from './createDryRunTemplateAction';\nimport { createListScaffolderActionsAction } from './createListScaffolderActionsAction';\n\nexport const createScaffolderActions = (options: {\n actionsRegistry: ActionsRegistryService;\n scaffolderService: ScaffolderService;\n auth: AuthService;\n}) => {\n createListScaffolderTasksAction({\n actionsRegistry: options.actionsRegistry,\n auth: options.auth,\n scaffolderService: options.scaffolderService,\n });\n createDryRunTemplateAction(options);\n createListScaffolderActionsAction(options);\n};\n"],"names":["createListScaffolderTasksAction","createDryRunTemplateAction","createListScaffolderActionsAction"],"mappings":";;;;;;AAsBO,MAAM,uBAAA,GAA0B,CAAC,OAAA,KAIlC;AACJ,EAAAA,yDAAA,CAAgC;AAAA,IAC9B,iBAAiB,OAAA,CAAQ,eAAA;AAAA,IACzB,MAAM,OAAA,CAAQ,IAAA;AAAA,IACd,mBAAmB,OAAA,CAAQ;AAAA,GAC5B,CAAA;AACD,EAAAC,qDAAA,CAA2B,OAAO,CAAA;AAClC,EAAAC,mEAAA,CAAkC,OAAO,CAAA;AAC3C;;;;"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var errors = require('@backstage/errors');
|
|
4
|
+
|
|
5
|
+
const createListScaffolderTasksAction = ({
|
|
6
|
+
actionsRegistry,
|
|
7
|
+
auth,
|
|
8
|
+
scaffolderService
|
|
9
|
+
}) => {
|
|
10
|
+
actionsRegistry.register({
|
|
11
|
+
name: "list-scaffolder-tasks",
|
|
12
|
+
title: "List Scaffolder Tasks",
|
|
13
|
+
attributes: {
|
|
14
|
+
destructive: false,
|
|
15
|
+
readOnly: true,
|
|
16
|
+
idempotent: true
|
|
17
|
+
},
|
|
18
|
+
description: `
|
|
19
|
+
This allows you to list scaffolder tasks that have been created.
|
|
20
|
+
Each task has a unique id, specification, and status (one of open, processing, completed, failed, cancelled, skipped).
|
|
21
|
+
Each task includes a timestamp for when it was created, and an optional last heartbeat timestamp indicating the most recent activity.
|
|
22
|
+
Set owned to true to return only tasks created by the current user; omit or set to false for all tasks the credentials can see.
|
|
23
|
+
Pagination is supported via limit and offset.
|
|
24
|
+
`,
|
|
25
|
+
schema: {
|
|
26
|
+
input: (z) => z.object({
|
|
27
|
+
owned: z.boolean().optional().default(false).describe(
|
|
28
|
+
"If true, return only tasks created by the current user. Requires a user identity."
|
|
29
|
+
),
|
|
30
|
+
limit: z.number().int().min(1).max(1e3).describe("The maximum number of tasks to return for pagination").optional(),
|
|
31
|
+
offset: z.number().int().min(0).describe("The offset to start from for pagination").optional()
|
|
32
|
+
}),
|
|
33
|
+
output: (z) => z.object({
|
|
34
|
+
tasks: z.array(
|
|
35
|
+
z.object({
|
|
36
|
+
id: z.string().describe("The task identifier"),
|
|
37
|
+
spec: z.unknown().describe("The task specification"),
|
|
38
|
+
status: z.string().describe(
|
|
39
|
+
"Task status: open, processing, completed, failed, cancelled, or skipped"
|
|
40
|
+
),
|
|
41
|
+
createdAt: z.string().describe("Timestamp when the task was created"),
|
|
42
|
+
lastHeartbeatAt: z.string().optional().describe("Timestamp of the last heartbeat")
|
|
43
|
+
})
|
|
44
|
+
).describe("The list of scaffolder tasks"),
|
|
45
|
+
totalTasks: z.number().describe("Total number of tasks matching the filter")
|
|
46
|
+
}).describe("Object containing a tasks array and totalTasks count")
|
|
47
|
+
},
|
|
48
|
+
action: async ({ input, credentials }) => {
|
|
49
|
+
if (input.owned && !auth.isPrincipal(credentials, "user")) {
|
|
50
|
+
throw new errors.NotAllowedError(
|
|
51
|
+
"Filtering by owned tasks requires a user identity."
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
const createdBy = input.owned && auth.isPrincipal(credentials, "user") ? credentials.principal.userEntityRef : void 0;
|
|
55
|
+
const { items, totalItems } = await scaffolderService.listTasks(
|
|
56
|
+
{
|
|
57
|
+
createdBy,
|
|
58
|
+
limit: input.limit,
|
|
59
|
+
offset: input.offset
|
|
60
|
+
},
|
|
61
|
+
{ credentials }
|
|
62
|
+
);
|
|
63
|
+
return {
|
|
64
|
+
output: {
|
|
65
|
+
tasks: items.map((task) => ({
|
|
66
|
+
id: task.id,
|
|
67
|
+
spec: task.spec,
|
|
68
|
+
status: task.status,
|
|
69
|
+
createdAt: task.createdAt,
|
|
70
|
+
lastHeartbeatAt: task.lastHeartbeatAt
|
|
71
|
+
})),
|
|
72
|
+
totalTasks: totalItems
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
exports.createListScaffolderTasksAction = createListScaffolderTasksAction;
|
|
80
|
+
//# sourceMappingURL=listScaffolderTasksAction.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"listScaffolderTasksAction.cjs.js","sources":["../../src/actions/listScaffolderTasksAction.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { ActionsRegistryService } from '@backstage/backend-plugin-api/alpha';\nimport { AuthService } from '@backstage/backend-plugin-api';\nimport { NotAllowedError } from '@backstage/errors';\nimport { ScaffolderService } from '@backstage/plugin-scaffolder-node';\n\nexport const createListScaffolderTasksAction = ({\n actionsRegistry,\n auth,\n scaffolderService,\n}: {\n actionsRegistry: ActionsRegistryService;\n auth: AuthService;\n scaffolderService: ScaffolderService;\n}) => {\n actionsRegistry.register({\n name: 'list-scaffolder-tasks',\n title: 'List Scaffolder Tasks',\n attributes: {\n destructive: false,\n readOnly: true,\n idempotent: true,\n },\n description: `\nThis allows you to list scaffolder tasks that have been created.\nEach task has a unique id, specification, and status (one of open, processing, completed, failed, cancelled, skipped).\nEach task includes a timestamp for when it was created, and an optional last heartbeat timestamp indicating the most recent activity.\nSet owned to true to return only tasks created by the current user; omit or set to false for all tasks the credentials can see.\nPagination is supported via limit and offset.\n `,\n schema: {\n input: z =>\n z.object({\n owned: z\n .boolean()\n .optional()\n .default(false)\n .describe(\n 'If true, return only tasks created by the current user. Requires a user identity.',\n ),\n limit: z\n .number()\n .int()\n .min(1)\n .max(1000)\n .describe('The maximum number of tasks to return for pagination')\n .optional(),\n offset: z\n .number()\n .int()\n .min(0)\n .describe('The offset to start from for pagination')\n .optional(),\n }),\n output: z =>\n z\n .object({\n tasks: z\n .array(\n z.object({\n id: z.string().describe('The task identifier'),\n spec: z.unknown().describe('The task specification'),\n status: z\n .string()\n .describe(\n 'Task status: open, processing, completed, failed, cancelled, or skipped',\n ),\n createdAt: z\n .string()\n .describe('Timestamp when the task was created'),\n lastHeartbeatAt: z\n .string()\n .optional()\n .describe('Timestamp of the last heartbeat'),\n }),\n )\n .describe('The list of scaffolder tasks'),\n totalTasks: z\n .number()\n .describe('Total number of tasks matching the filter'),\n })\n .describe('Object containing a tasks array and totalTasks count'),\n },\n action: async ({ input, credentials }) => {\n if (input.owned && !auth.isPrincipal(credentials, 'user')) {\n throw new NotAllowedError(\n 'Filtering by owned tasks requires a user identity.',\n );\n }\n\n const createdBy =\n input.owned && auth.isPrincipal(credentials, 'user')\n ? credentials.principal.userEntityRef\n : undefined;\n\n const { items, totalItems } = await scaffolderService.listTasks(\n {\n createdBy,\n limit: input.limit,\n offset: input.offset,\n },\n { credentials },\n );\n\n return {\n output: {\n tasks: items.map(task => ({\n id: task.id,\n spec: task.spec,\n status: task.status,\n createdAt: task.createdAt,\n lastHeartbeatAt: task.lastHeartbeatAt,\n })),\n totalTasks: totalItems,\n },\n };\n },\n });\n};\n"],"names":["NotAllowedError"],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
var backendOpenapiUtils = require('@backstage/backend-openapi-utils');
|
|
4
4
|
|
|
5
5
|
const spec = {
|
|
6
|
-
openapi: "3.0
|
|
6
|
+
openapi: "3.1.0",
|
|
7
7
|
info: {
|
|
8
8
|
title: "scaffolder",
|
|
9
9
|
version: "1",
|
|
@@ -50,7 +50,6 @@ const spec = {
|
|
|
50
50
|
name: "kind",
|
|
51
51
|
in: "path",
|
|
52
52
|
required: true,
|
|
53
|
-
allowReserved: true,
|
|
54
53
|
schema: {
|
|
55
54
|
type: "string"
|
|
56
55
|
}
|
|
@@ -70,7 +69,6 @@ const spec = {
|
|
|
70
69
|
name: "namespace",
|
|
71
70
|
in: "path",
|
|
72
71
|
required: true,
|
|
73
|
-
allowReserved: true,
|
|
74
72
|
schema: {
|
|
75
73
|
type: "string"
|
|
76
74
|
}
|
|
@@ -79,7 +77,6 @@ const spec = {
|
|
|
79
77
|
name: "name",
|
|
80
78
|
in: "path",
|
|
81
79
|
required: true,
|
|
82
|
-
allowReserved: true,
|
|
83
80
|
schema: {
|
|
84
81
|
type: "string"
|
|
85
82
|
}
|
|
@@ -125,7 +122,6 @@ const spec = {
|
|
|
125
122
|
name: "taskId",
|
|
126
123
|
in: "path",
|
|
127
124
|
required: true,
|
|
128
|
-
allowReserved: true,
|
|
129
125
|
schema: {
|
|
130
126
|
type: "string"
|
|
131
127
|
}
|
|
@@ -305,8 +301,7 @@ const spec = {
|
|
|
305
301
|
type: "string"
|
|
306
302
|
},
|
|
307
303
|
{
|
|
308
|
-
type: "
|
|
309
|
-
nullable: true
|
|
304
|
+
type: "null"
|
|
310
305
|
}
|
|
311
306
|
],
|
|
312
307
|
description: "A type representing all allowed JSON primitive values."
|
|
@@ -580,8 +575,14 @@ const spec = {
|
|
|
580
575
|
type: "string"
|
|
581
576
|
},
|
|
582
577
|
value: {
|
|
583
|
-
|
|
584
|
-
|
|
578
|
+
anyOf: [
|
|
579
|
+
{
|
|
580
|
+
type: "object"
|
|
581
|
+
},
|
|
582
|
+
{
|
|
583
|
+
type: "null"
|
|
584
|
+
}
|
|
585
|
+
]
|
|
585
586
|
}
|
|
586
587
|
},
|
|
587
588
|
required: ["value"],
|
|
@@ -990,6 +991,25 @@ const spec = {
|
|
|
990
991
|
}
|
|
991
992
|
}
|
|
992
993
|
}
|
|
994
|
+
},
|
|
995
|
+
"400": {
|
|
996
|
+
description: "Validation errors.",
|
|
997
|
+
content: {
|
|
998
|
+
"application/json": {
|
|
999
|
+
schema: {
|
|
1000
|
+
type: "object",
|
|
1001
|
+
properties: {
|
|
1002
|
+
errors: {
|
|
1003
|
+
type: "array",
|
|
1004
|
+
items: {
|
|
1005
|
+
$ref: "#/components/schemas/ValidationError"
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
},
|
|
1009
|
+
required: ["errors"]
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
993
1013
|
}
|
|
994
1014
|
},
|
|
995
1015
|
security: [
|
|
@@ -1240,7 +1260,6 @@ const spec = {
|
|
|
1240
1260
|
in: "path",
|
|
1241
1261
|
name: "provider",
|
|
1242
1262
|
required: true,
|
|
1243
|
-
allowReserved: true,
|
|
1244
1263
|
schema: {
|
|
1245
1264
|
type: "string"
|
|
1246
1265
|
}
|
|
@@ -1249,7 +1268,6 @@ const spec = {
|
|
|
1249
1268
|
in: "path",
|
|
1250
1269
|
name: "resource",
|
|
1251
1270
|
required: true,
|
|
1252
|
-
allowReserved: true,
|
|
1253
1271
|
schema: {
|
|
1254
1272
|
type: "string"
|
|
1255
1273
|
}
|