@backstage/plugin-scaffolder-backend 1.27.0-next.2 → 1.27.0

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.
Files changed (31) hide show
  1. package/CHANGELOG.md +82 -0
  2. package/config.d.ts +4 -4
  3. package/dist/ScaffolderPlugin.cjs.js +2 -0
  4. package/dist/ScaffolderPlugin.cjs.js.map +1 -1
  5. package/dist/index.cjs.js +2 -0
  6. package/dist/index.cjs.js.map +1 -1
  7. package/dist/index.d.ts +22 -2
  8. package/dist/scaffolder/actions/builtin/catalog/fetch.cjs.js +11 -11
  9. package/dist/scaffolder/actions/builtin/catalog/fetch.cjs.js.map +1 -1
  10. package/dist/scaffolder/actions/builtin/catalog/write.cjs.js +4 -4
  11. package/dist/scaffolder/actions/builtin/catalog/write.cjs.js.map +1 -1
  12. package/dist/scaffolder/actions/builtin/createBuiltinActions.cjs.js +2 -0
  13. package/dist/scaffolder/actions/builtin/createBuiltinActions.cjs.js.map +1 -1
  14. package/dist/scaffolder/actions/builtin/debug/log.cjs.js +9 -9
  15. package/dist/scaffolder/actions/builtin/debug/log.cjs.js.map +1 -1
  16. package/dist/scaffolder/actions/builtin/filesystem/read.cjs.js +68 -0
  17. package/dist/scaffolder/actions/builtin/filesystem/read.cjs.js.map +1 -0
  18. package/dist/scaffolder/dryrun/DecoratedActionsRegistry.cjs.js +1 -0
  19. package/dist/scaffolder/dryrun/DecoratedActionsRegistry.cjs.js.map +1 -1
  20. package/dist/scaffolder/dryrun/createDryRunner.cjs.js +10 -12
  21. package/dist/scaffolder/dryrun/createDryRunner.cjs.js.map +1 -1
  22. package/dist/scaffolder/tasks/NunjucksWorkflowRunner.cjs.js +4 -3
  23. package/dist/scaffolder/tasks/NunjucksWorkflowRunner.cjs.js.map +1 -1
  24. package/dist/scaffolder/tasks/StorageTaskBroker.cjs.js +4 -11
  25. package/dist/scaffolder/tasks/StorageTaskBroker.cjs.js.map +1 -1
  26. package/dist/service/router.cjs.js +26 -8
  27. package/dist/service/router.cjs.js.map +1 -1
  28. package/dist/service/rules.cjs.js +11 -11
  29. package/dist/service/rules.cjs.js.map +1 -1
  30. package/package.json +42 -33
  31. package/alpha/package.json +0 -6
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read.cjs.js","sources":["../../../../../src/scaffolder/actions/builtin/filesystem/read.ts"],"sourcesContent":["/*\n * Copyright 2024 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 { createTemplateAction } from '@backstage/plugin-scaffolder-node';\nimport z from 'zod';\nimport { resolveSafeChildPath } from '@backstage/backend-plugin-api';\nimport fs from 'fs/promises';\nimport path from 'path';\n\nconst contentSchema = z.object({\n name: z.string().describe('Name of the file or directory'),\n path: z\n .string()\n .describe('path to the file or directory relative to the workspace'),\n fullPath: z.string().describe('full path to the file or directory'),\n});\ntype Content = z.infer<typeof contentSchema>;\n\n/**\n * Creates new action that enables reading directories in the workspace.\n * @public\n */\nexport const createFilesystemReadDirAction = () => {\n return createTemplateAction({\n id: 'fs:readdir',\n description: 'Reads files and directories from the workspace',\n supportsDryRun: true,\n schema: {\n input: z.object({\n paths: z.array(z.string().min(1)),\n recursive: z.boolean().default(false),\n }),\n output: z.object({\n files: z.array(contentSchema),\n folders: z.array(contentSchema),\n }),\n },\n async handler(ctx) {\n const files: Content[] = [];\n const folders: Content[] = [];\n\n for (const localPath of ctx.input.paths) {\n const fullWorkspacePath = resolveSafeChildPath(\n ctx.workspacePath,\n localPath,\n );\n const content = await fs.readdir(fullWorkspacePath, {\n recursive: ctx.input.recursive,\n withFileTypes: true,\n });\n for (const dirent of content) {\n const fullPath = path.join(dirent.parentPath, dirent.name);\n const element = {\n name: dirent.name,\n path: path.relative(ctx.workspacePath, fullPath),\n fullPath,\n };\n if (dirent.isDirectory()) {\n folders.push(element);\n } else {\n files.push(element);\n }\n }\n }\n\n ctx.output('files', files);\n ctx.output('folders', folders);\n },\n });\n};\n"],"names":["z","createTemplateAction","resolveSafeChildPath","fs","path"],"mappings":";;;;;;;;;;;;;;AAqBA,MAAM,aAAA,GAAgBA,mBAAE,MAAO,CAAA;AAAA,EAC7B,IAAM,EAAAA,kBAAA,CAAE,MAAO,EAAA,CAAE,SAAS,+BAA+B,CAAA;AAAA,EACzD,IAAM,EAAAA,kBAAA,CACH,MAAO,EAAA,CACP,SAAS,yDAAyD,CAAA;AAAA,EACrE,QAAU,EAAAA,kBAAA,CAAE,MAAO,EAAA,CAAE,SAAS,oCAAoC;AACpE,CAAC,CAAA;AAOM,MAAM,gCAAgC,MAAM;AACjD,EAAA,OAAOC,yCAAqB,CAAA;AAAA,IAC1B,EAAI,EAAA,YAAA;AAAA,IACJ,WAAa,EAAA,gDAAA;AAAA,IACb,cAAgB,EAAA,IAAA;AAAA,IAChB,MAAQ,EAAA;AAAA,MACN,KAAA,EAAOD,mBAAE,MAAO,CAAA;AAAA,QACd,KAAA,EAAOA,mBAAE,KAAM,CAAAA,kBAAA,CAAE,QAAS,CAAA,GAAA,CAAI,CAAC,CAAC,CAAA;AAAA,QAChC,SAAW,EAAAA,kBAAA,CAAE,OAAQ,EAAA,CAAE,QAAQ,KAAK;AAAA,OACrC,CAAA;AAAA,MACD,MAAA,EAAQA,mBAAE,MAAO,CAAA;AAAA,QACf,KAAA,EAAOA,kBAAE,CAAA,KAAA,CAAM,aAAa,CAAA;AAAA,QAC5B,OAAA,EAASA,kBAAE,CAAA,KAAA,CAAM,aAAa;AAAA,OAC/B;AAAA,KACH;AAAA,IACA,MAAM,QAAQ,GAAK,EAAA;AACjB,MAAA,MAAM,QAAmB,EAAC;AAC1B,MAAA,MAAM,UAAqB,EAAC;AAE5B,MAAW,KAAA,MAAA,SAAA,IAAa,GAAI,CAAA,KAAA,CAAM,KAAO,EAAA;AACvC,QAAA,MAAM,iBAAoB,GAAAE,qCAAA;AAAA,UACxB,GAAI,CAAA,aAAA;AAAA,UACJ;AAAA,SACF;AACA,QAAA,MAAM,OAAU,GAAA,MAAMC,mBAAG,CAAA,OAAA,CAAQ,iBAAmB,EAAA;AAAA,UAClD,SAAA,EAAW,IAAI,KAAM,CAAA,SAAA;AAAA,UACrB,aAAe,EAAA;AAAA,SAChB,CAAA;AACD,QAAA,KAAA,MAAW,UAAU,OAAS,EAAA;AAC5B,UAAA,MAAM,WAAWC,qBAAK,CAAA,IAAA,CAAK,MAAO,CAAA,UAAA,EAAY,OAAO,IAAI,CAAA;AACzD,UAAA,MAAM,OAAU,GAAA;AAAA,YACd,MAAM,MAAO,CAAA,IAAA;AAAA,YACb,IAAM,EAAAA,qBAAA,CAAK,QAAS,CAAA,GAAA,CAAI,eAAe,QAAQ,CAAA;AAAA,YAC/C;AAAA,WACF;AACA,UAAI,IAAA,MAAA,CAAO,aAAe,EAAA;AACxB,YAAA,OAAA,CAAQ,KAAK,OAAO,CAAA;AAAA,WACf,MAAA;AACL,YAAA,KAAA,CAAM,KAAK,OAAO,CAAA;AAAA;AACpB;AACF;AAGF,MAAI,GAAA,CAAA,MAAA,CAAO,SAAS,KAAK,CAAA;AACzB,MAAI,GAAA,CAAA,MAAA,CAAO,WAAW,OAAO,CAAA;AAAA;AAC/B,GACD,CAAA;AACH;;;;"}
@@ -26,6 +26,7 @@ require('../actions/builtin/fetch/template.examples.cjs.js');
26
26
  require('../actions/builtin/fetch/templateFile.examples.cjs.js');
27
27
  require('../actions/builtin/filesystem/delete.examples.cjs.js');
28
28
  require('../actions/builtin/filesystem/rename.examples.cjs.js');
29
+ require('../actions/builtin/filesystem/read.cjs.js');
29
30
  require('@backstage/plugin-scaffolder-backend-module-github');
30
31
  require('@backstage/plugin-scaffolder-backend-module-azure');
31
32
  require('@backstage/plugin-scaffolder-backend-module-bitbucket');
@@ -1 +1 @@
1
- {"version":3,"file":"DecoratedActionsRegistry.cjs.js","sources":["../../../src/scaffolder/dryrun/DecoratedActionsRegistry.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 { TemplateAction } from '@backstage/plugin-scaffolder-node';\nimport { TemplateActionRegistry } from '../actions';\n\n/** @internal */\nexport class DecoratedActionsRegistry extends TemplateActionRegistry {\n constructor(\n private readonly innerRegistry: TemplateActionRegistry,\n extraActions: Array<TemplateAction>,\n ) {\n super();\n for (const action of extraActions) {\n this.register(action);\n }\n }\n\n get(actionId: string): TemplateAction {\n try {\n return super.get(actionId);\n } catch {\n return this.innerRegistry.get(actionId);\n }\n }\n}\n"],"names":["TemplateActionRegistry"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoBO,MAAM,iCAAiCA,6CAAuB,CAAA;AAAA,EACnE,WAAA,CACmB,eACjB,YACA,EAAA;AACA,IAAM,KAAA,EAAA;AAHW,IAAA,IAAA,CAAA,aAAA,GAAA,aAAA;AAIjB,IAAA,KAAA,MAAW,UAAU,YAAc,EAAA;AACjC,MAAA,IAAA,CAAK,SAAS,MAAM,CAAA;AAAA;AACtB;AACF,EAEA,IAAI,QAAkC,EAAA;AACpC,IAAI,IAAA;AACF,MAAO,OAAA,KAAA,CAAM,IAAI,QAAQ,CAAA;AAAA,KACnB,CAAA,MAAA;AACN,MAAO,OAAA,IAAA,CAAK,aAAc,CAAA,GAAA,CAAI,QAAQ,CAAA;AAAA;AACxC;AAEJ;;;;"}
1
+ {"version":3,"file":"DecoratedActionsRegistry.cjs.js","sources":["../../../src/scaffolder/dryrun/DecoratedActionsRegistry.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 { TemplateAction } from '@backstage/plugin-scaffolder-node';\nimport { TemplateActionRegistry } from '../actions';\n\n/** @internal */\nexport class DecoratedActionsRegistry extends TemplateActionRegistry {\n constructor(\n private readonly innerRegistry: TemplateActionRegistry,\n extraActions: Array<TemplateAction>,\n ) {\n super();\n for (const action of extraActions) {\n this.register(action);\n }\n }\n\n get(actionId: string): TemplateAction {\n try {\n return super.get(actionId);\n } catch {\n return this.innerRegistry.get(actionId);\n }\n }\n}\n"],"names":["TemplateActionRegistry"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoBO,MAAM,iCAAiCA,6CAAuB,CAAA;AAAA,EACnE,WAAA,CACmB,eACjB,YACA,EAAA;AACA,IAAM,KAAA,EAAA;AAHW,IAAA,IAAA,CAAA,aAAA,GAAA,aAAA;AAIjB,IAAA,KAAA,MAAW,UAAU,YAAc,EAAA;AACjC,MAAA,IAAA,CAAK,SAAS,MAAM,CAAA;AAAA;AACtB;AACF,EAEA,IAAI,QAAkC,EAAA;AACpC,IAAI,IAAA;AACF,MAAO,OAAA,KAAA,CAAM,IAAI,QAAQ,CAAA;AAAA,KACnB,CAAA,MAAA;AACN,MAAO,OAAA,IAAA,CAAK,aAAc,CAAA,GAAA,CAAI,QAAQ,CAAA;AAAA;AACxC;AAEJ;;;;"}
@@ -1,15 +1,16 @@
1
1
  'use strict';
2
2
 
3
- var uuid = require('uuid');
4
3
  var url = require('url');
5
4
  var pluginScaffolderNode = require('@backstage/plugin-scaffolder-node');
5
+ var path = require('path');
6
6
  var NunjucksWorkflowRunner = require('../tasks/NunjucksWorkflowRunner.cjs.js');
7
7
  var DecoratedActionsRegistry = require('./DecoratedActionsRegistry.cjs.js');
8
8
  var fs = require('fs-extra');
9
- var backendPluginApi = require('@backstage/backend-plugin-api');
9
+ var uuid = require('uuid');
10
10
 
11
11
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
12
12
 
13
+ var path__default = /*#__PURE__*/_interopDefaultCompat(path);
13
14
  var fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
14
15
 
15
16
  function createDryRunner(options) {
@@ -29,12 +30,14 @@ function createDryRunner(options) {
29
30
  })
30
31
  ])
31
32
  });
33
+ const baseUrl = input.templateInfo.baseUrl;
34
+ if (!baseUrl) {
35
+ throw new Error("baseUrl is required");
36
+ }
37
+ const basePath = url.fileURLToPath(new URL(baseUrl));
38
+ const contentsPath = path__default.default.dirname(basePath);
32
39
  const dryRunId = uuid.v4();
33
40
  const log = new Array();
34
- const contentsPath = backendPluginApi.resolveSafeChildPath(
35
- options.workingDirectory,
36
- `dry-run-content-${dryRunId}`
37
- );
38
41
  try {
39
42
  await pluginScaffolderNode.deserializeDirectoryContents(contentsPath, input.directoryContents);
40
43
  const abortSignal = new AbortController().signal;
@@ -49,12 +52,7 @@ function createDryRunner(options) {
49
52
  action: "dry-run:extract"
50
53
  }
51
54
  ],
52
- templateInfo: {
53
- entityRef: "template:default/dry-run",
54
- baseUrl: url.pathToFileURL(
55
- backendPluginApi.resolveSafeChildPath(contentsPath, "template.yaml")
56
- ).toString()
57
- }
55
+ templateInfo: input.templateInfo
58
56
  },
59
57
  secrets: input.secrets,
60
58
  getInitiatorCredentials: () => Promise.resolve(input.credentials),
@@ -1 +1 @@
1
- {"version":3,"file":"createDryRunner.cjs.js","sources":["../../../src/scaffolder/dryrun/createDryRunner.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 { ScmIntegrations } from '@backstage/integration';\nimport { TaskSpec } from '@backstage/plugin-scaffolder-common';\nimport { JsonObject } from '@backstage/types';\nimport { v4 as uuid } from 'uuid';\nimport { pathToFileURL } from 'url';\nimport { Logger } from 'winston';\nimport {\n createTemplateAction,\n TaskSecrets,\n TemplateFilter,\n TemplateGlobal,\n deserializeDirectoryContents,\n SerializedFile,\n serializeDirectoryContents,\n} from '@backstage/plugin-scaffolder-node';\nimport { TemplateActionRegistry } from '../actions';\nimport { NunjucksWorkflowRunner } from '../tasks/NunjucksWorkflowRunner';\nimport { DecoratedActionsRegistry } from './DecoratedActionsRegistry';\nimport fs from 'fs-extra';\nimport { PermissionEvaluator } from '@backstage/plugin-permission-common';\nimport {\n BackstageCredentials,\n resolveSafeChildPath,\n} from '@backstage/backend-plugin-api';\nimport type { UserEntity } from '@backstage/catalog-model';\n\ninterface DryRunInput {\n spec: TaskSpec;\n secrets?: TaskSecrets;\n directoryContents: SerializedFile[];\n credentials: BackstageCredentials;\n user?: {\n entity?: UserEntity;\n ref?: string;\n };\n}\n\ninterface DryRunResult {\n log: Array<{ body: JsonObject }>;\n directoryContents: SerializedFile[];\n output: JsonObject;\n}\n\n/** @internal */\nexport type TemplateTesterCreateOptions = {\n logger: Logger;\n integrations: ScmIntegrations;\n actionRegistry: TemplateActionRegistry;\n workingDirectory: string;\n additionalTemplateFilters?: Record<string, TemplateFilter>;\n additionalTemplateGlobals?: Record<string, TemplateGlobal>;\n permissions?: PermissionEvaluator;\n};\n\n/**\n * Executes a dry-run of the provided template.\n *\n * The provided content will be extracted into a temporary directory\n * which is then use as the base for any relative file fetch paths.\n *\n * @internal\n */\nexport function createDryRunner(options: TemplateTesterCreateOptions) {\n return async function dryRun(input: DryRunInput): Promise<DryRunResult> {\n let contentPromise;\n\n const workflowRunner = new NunjucksWorkflowRunner({\n ...options,\n actionRegistry: new DecoratedActionsRegistry(options.actionRegistry, [\n createTemplateAction({\n id: 'dry-run:extract',\n supportsDryRun: true,\n async handler(ctx) {\n contentPromise = serializeDirectoryContents(ctx.workspacePath);\n await contentPromise.catch(() => {});\n },\n }),\n ]),\n });\n\n const dryRunId = uuid();\n const log = new Array<{ body: JsonObject }>();\n const contentsPath = resolveSafeChildPath(\n options.workingDirectory,\n `dry-run-content-${dryRunId}`,\n );\n\n try {\n await deserializeDirectoryContents(contentsPath, input.directoryContents);\n\n const abortSignal = new AbortController().signal;\n\n const result = await workflowRunner.execute({\n spec: {\n ...input.spec,\n steps: [\n ...input.spec.steps,\n {\n id: dryRunId,\n name: 'dry-run:extract',\n action: 'dry-run:extract',\n },\n ],\n templateInfo: {\n entityRef: 'template:default/dry-run',\n baseUrl: pathToFileURL(\n resolveSafeChildPath(contentsPath, 'template.yaml'),\n ).toString(),\n },\n },\n secrets: input.secrets,\n getInitiatorCredentials: () => Promise.resolve(input.credentials),\n // No need to update this at the end of the run, so just hard-code it\n done: false,\n isDryRun: true,\n getWorkspaceName: async () => `dry-run-${dryRunId}`,\n cancelSignal: abortSignal,\n async emitLog(message: string, logMetadata?: JsonObject) {\n if (logMetadata?.stepId === dryRunId) {\n return;\n }\n log.push({\n body: {\n ...logMetadata,\n message,\n },\n });\n },\n complete: async () => {\n throw new Error('Not implemented');\n },\n });\n\n if (!contentPromise) {\n throw new Error('Content extraction step was skipped');\n }\n const directoryContents = await contentPromise;\n\n return {\n log,\n directoryContents,\n output: result.output,\n };\n } finally {\n await fs.remove(contentsPath);\n }\n };\n}\n"],"names":["NunjucksWorkflowRunner","DecoratedActionsRegistry","createTemplateAction","serializeDirectoryContents","uuid","resolveSafeChildPath","deserializeDirectoryContents","pathToFileURL","fs"],"mappings":";;;;;;;;;;;;;;AA8EO,SAAS,gBAAgB,OAAsC,EAAA;AACpE,EAAO,OAAA,eAAe,OAAO,KAA2C,EAAA;AACtE,IAAI,IAAA,cAAA;AAEJ,IAAM,MAAA,cAAA,GAAiB,IAAIA,6CAAuB,CAAA;AAAA,MAChD,GAAG,OAAA;AAAA,MACH,cAAgB,EAAA,IAAIC,iDAAyB,CAAA,OAAA,CAAQ,cAAgB,EAAA;AAAA,QACnEC,yCAAqB,CAAA;AAAA,UACnB,EAAI,EAAA,iBAAA;AAAA,UACJ,cAAgB,EAAA,IAAA;AAAA,UAChB,MAAM,QAAQ,GAAK,EAAA;AACjB,YAAiB,cAAA,GAAAC,+CAAA,CAA2B,IAAI,aAAa,CAAA;AAC7D,YAAM,MAAA,cAAA,CAAe,MAAM,MAAM;AAAA,aAAE,CAAA;AAAA;AACrC,SACD;AAAA,OACF;AAAA,KACF,CAAA;AAED,IAAA,MAAM,WAAWC,OAAK,EAAA;AACtB,IAAM,MAAA,GAAA,GAAM,IAAI,KAA4B,EAAA;AAC5C,IAAA,MAAM,YAAe,GAAAC,qCAAA;AAAA,MACnB,OAAQ,CAAA,gBAAA;AAAA,MACR,mBAAmB,QAAQ,CAAA;AAAA,KAC7B;AAEA,IAAI,IAAA;AACF,MAAM,MAAAC,iDAAA,CAA6B,YAAc,EAAA,KAAA,CAAM,iBAAiB,CAAA;AAExE,MAAM,MAAA,WAAA,GAAc,IAAI,eAAA,EAAkB,CAAA,MAAA;AAE1C,MAAM,MAAA,MAAA,GAAS,MAAM,cAAA,CAAe,OAAQ,CAAA;AAAA,QAC1C,IAAM,EAAA;AAAA,UACJ,GAAG,KAAM,CAAA,IAAA;AAAA,UACT,KAAO,EAAA;AAAA,YACL,GAAG,MAAM,IAAK,CAAA,KAAA;AAAA,YACd;AAAA,cACE,EAAI,EAAA,QAAA;AAAA,cACJ,IAAM,EAAA,iBAAA;AAAA,cACN,MAAQ,EAAA;AAAA;AACV,WACF;AAAA,UACA,YAAc,EAAA;AAAA,YACZ,SAAW,EAAA,0BAAA;AAAA,YACX,OAAS,EAAAC,iBAAA;AAAA,cACPF,qCAAA,CAAqB,cAAc,eAAe;AAAA,cAClD,QAAS;AAAA;AACb,SACF;AAAA,QACA,SAAS,KAAM,CAAA,OAAA;AAAA,QACf,uBAAyB,EAAA,MAAM,OAAQ,CAAA,OAAA,CAAQ,MAAM,WAAW,CAAA;AAAA;AAAA,QAEhE,IAAM,EAAA,KAAA;AAAA,QACN,QAAU,EAAA,IAAA;AAAA,QACV,gBAAA,EAAkB,YAAY,CAAA,QAAA,EAAW,QAAQ,CAAA,CAAA;AAAA,QACjD,YAAc,EAAA,WAAA;AAAA,QACd,MAAM,OAAQ,CAAA,OAAA,EAAiB,WAA0B,EAAA;AACvD,UAAI,IAAA,WAAA,EAAa,WAAW,QAAU,EAAA;AACpC,YAAA;AAAA;AAEF,UAAA,GAAA,CAAI,IAAK,CAAA;AAAA,YACP,IAAM,EAAA;AAAA,cACJ,GAAG,WAAA;AAAA,cACH;AAAA;AACF,WACD,CAAA;AAAA,SACH;AAAA,QACA,UAAU,YAAY;AACpB,UAAM,MAAA,IAAI,MAAM,iBAAiB,CAAA;AAAA;AACnC,OACD,CAAA;AAED,MAAA,IAAI,CAAC,cAAgB,EAAA;AACnB,QAAM,MAAA,IAAI,MAAM,qCAAqC,CAAA;AAAA;AAEvD,MAAA,MAAM,oBAAoB,MAAM,cAAA;AAEhC,MAAO,OAAA;AAAA,QACL,GAAA;AAAA,QACA,iBAAA;AAAA,QACA,QAAQ,MAAO,CAAA;AAAA,OACjB;AAAA,KACA,SAAA;AACA,MAAM,MAAAG,mBAAA,CAAG,OAAO,YAAY,CAAA;AAAA;AAC9B,GACF;AACF;;;;"}
1
+ {"version":3,"file":"createDryRunner.cjs.js","sources":["../../../src/scaffolder/dryrun/createDryRunner.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 { ScmIntegrations } from '@backstage/integration';\nimport { TaskSpec, TemplateInfo } from '@backstage/plugin-scaffolder-common';\nimport { JsonObject } from '@backstage/types';\nimport { fileURLToPath } from 'url';\nimport { Logger } from 'winston';\nimport {\n createTemplateAction,\n TaskSecrets,\n TemplateFilter,\n TemplateGlobal,\n deserializeDirectoryContents,\n SerializedFile,\n serializeDirectoryContents,\n} from '@backstage/plugin-scaffolder-node';\nimport path from 'path';\nimport { TemplateActionRegistry } from '../actions';\nimport { NunjucksWorkflowRunner } from '../tasks/NunjucksWorkflowRunner';\nimport { DecoratedActionsRegistry } from './DecoratedActionsRegistry';\nimport fs from 'fs-extra';\nimport { PermissionEvaluator } from '@backstage/plugin-permission-common';\nimport { BackstageCredentials } from '@backstage/backend-plugin-api';\nimport type { UserEntity } from '@backstage/catalog-model';\nimport { v4 as uuid } from 'uuid';\n\ninterface DryRunInput {\n spec: TaskSpec;\n templateInfo: TemplateInfo;\n secrets?: TaskSecrets;\n directoryContents: SerializedFile[];\n credentials: BackstageCredentials;\n user?: {\n entity?: UserEntity;\n ref?: string;\n };\n}\n\ninterface DryRunResult {\n log: Array<{ body: JsonObject }>;\n directoryContents: SerializedFile[];\n output: JsonObject;\n}\n\n/** @internal */\nexport type TemplateTesterCreateOptions = {\n logger: Logger;\n integrations: ScmIntegrations;\n actionRegistry: TemplateActionRegistry;\n workingDirectory: string;\n additionalTemplateFilters?: Record<string, TemplateFilter>;\n additionalTemplateGlobals?: Record<string, TemplateGlobal>;\n permissions?: PermissionEvaluator;\n};\n\n/**\n * Executes a dry-run of the provided template.\n *\n * The provided content will be extracted into a temporary directory\n * which is then use as the base for any relative file fetch paths.\n *\n * @internal\n */\nexport function createDryRunner(options: TemplateTesterCreateOptions) {\n return async function dryRun(input: DryRunInput): Promise<DryRunResult> {\n let contentPromise;\n\n const workflowRunner = new NunjucksWorkflowRunner({\n ...options,\n actionRegistry: new DecoratedActionsRegistry(options.actionRegistry, [\n createTemplateAction({\n id: 'dry-run:extract',\n supportsDryRun: true,\n async handler(ctx) {\n contentPromise = serializeDirectoryContents(ctx.workspacePath);\n await contentPromise.catch(() => {});\n },\n }),\n ]),\n });\n\n // Extracting contentsPath and dryRunId from the baseUrl\n const baseUrl = input.templateInfo.baseUrl;\n if (!baseUrl) {\n throw new Error('baseUrl is required');\n }\n const basePath = fileURLToPath(new URL(baseUrl));\n const contentsPath = path.dirname(basePath);\n const dryRunId = uuid();\n\n const log = new Array<{ body: JsonObject }>();\n\n try {\n await deserializeDirectoryContents(contentsPath, input.directoryContents);\n\n const abortSignal = new AbortController().signal;\n const result = await workflowRunner.execute({\n spec: {\n ...input.spec,\n steps: [\n ...input.spec.steps,\n {\n id: dryRunId,\n name: 'dry-run:extract',\n action: 'dry-run:extract',\n },\n ],\n templateInfo: input.templateInfo,\n },\n secrets: input.secrets,\n getInitiatorCredentials: () => Promise.resolve(input.credentials),\n // No need to update this at the end of the run, so just hard-code it\n done: false,\n isDryRun: true,\n getWorkspaceName: async () => `dry-run-${dryRunId}`,\n cancelSignal: abortSignal,\n async emitLog(message: string, logMetadata?: JsonObject) {\n if (logMetadata?.stepId === dryRunId) {\n return;\n }\n log.push({\n body: {\n ...logMetadata,\n message,\n },\n });\n },\n complete: async () => {\n throw new Error('Not implemented');\n },\n });\n\n if (!contentPromise) {\n throw new Error('Content extraction step was skipped');\n }\n const directoryContents = await contentPromise;\n\n return {\n log,\n directoryContents,\n output: result.output,\n };\n } finally {\n await fs.remove(contentsPath);\n }\n };\n}\n"],"names":["NunjucksWorkflowRunner","DecoratedActionsRegistry","createTemplateAction","serializeDirectoryContents","fileURLToPath","path","uuid","deserializeDirectoryContents","fs"],"mappings":"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"}
@@ -238,8 +238,9 @@ class NunjucksWorkflowRunner {
238
238
  logger: backendCommon.loggerToWinstonLogger(taskLogger),
239
239
  logStream: streamLogger,
240
240
  workspacePath,
241
- async checkpoint(keySuffix, fn) {
242
- const key = `v1.task.checkpoint.${step.id}.${keySuffix}`;
241
+ async checkpoint(opts) {
242
+ const { key: checkpointKey, fn } = opts;
243
+ const key = `v1.task.checkpoint.${step.id}.${checkpointKey}`;
243
244
  try {
244
245
  let prevValue;
245
246
  if (prevTaskState) {
@@ -253,7 +254,7 @@ class NunjucksWorkflowRunner {
253
254
  task.updateCheckpoint?.({
254
255
  key,
255
256
  status: "success",
256
- value
257
+ value: value ?? {}
257
258
  });
258
259
  }
259
260
  return value;
@@ -1 +1 @@
1
- {"version":3,"file":"NunjucksWorkflowRunner.cjs.js","sources":["../../../src/scaffolder/tasks/NunjucksWorkflowRunner.ts"],"sourcesContent":["/*\n * Copyright 2021 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 { ScmIntegrations } from '@backstage/integration';\nimport { TaskTrackType, WorkflowResponse, WorkflowRunner } from './types';\nimport * as winston from 'winston';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport nunjucks from 'nunjucks';\nimport { JsonArray, JsonObject, JsonValue } from '@backstage/types';\nimport { InputError, NotAllowedError, stringifyError } from '@backstage/errors';\nimport { PassThrough } from 'stream';\nimport { generateExampleOutput, isTruthy } from './helper';\nimport { validate as validateJsonSchema } from 'jsonschema';\nimport { TemplateActionRegistry } from '../actions';\nimport { metrics } from '@opentelemetry/api';\nimport {\n SecureTemplater,\n SecureTemplateRenderer,\n} from '../../lib/templating/SecureTemplater';\nimport {\n TaskRecovery,\n TaskSpec,\n TaskSpecV1beta3,\n TaskStep,\n} from '@backstage/plugin-scaffolder-common';\n\nimport {\n TemplateAction,\n TemplateFilter,\n TemplateGlobal,\n TaskContext,\n} from '@backstage/plugin-scaffolder-node';\nimport { createConditionAuthorizer } from '@backstage/plugin-permission-node';\nimport { UserEntity } from '@backstage/catalog-model';\nimport { createCounterMetric, createHistogramMetric } from '../../util/metrics';\nimport { createDefaultFilters } from '../../lib/templating/filters';\nimport {\n AuthorizeResult,\n PolicyDecision,\n} from '@backstage/plugin-permission-common';\nimport { scaffolderActionRules } from '../../service/rules';\nimport { actionExecutePermission } from '@backstage/plugin-scaffolder-common/alpha';\nimport { PermissionsService } from '@backstage/backend-plugin-api';\nimport { loggerToWinstonLogger } from '@backstage/backend-common';\nimport { BackstageLoggerTransport, WinstonLogger } from './logger';\n\ntype NunjucksWorkflowRunnerOptions = {\n workingDirectory: string;\n actionRegistry: TemplateActionRegistry;\n integrations: ScmIntegrations;\n logger: winston.Logger;\n additionalTemplateFilters?: Record<string, TemplateFilter>;\n additionalTemplateGlobals?: Record<string, TemplateGlobal>;\n permissions?: PermissionsService;\n};\n\ntype TemplateContext = {\n parameters: JsonObject;\n EXPERIMENTAL_recovery?: TaskRecovery;\n steps: {\n [stepName: string]: { output: { [outputName: string]: JsonValue } };\n };\n secrets?: Record<string, string>;\n user?: {\n entity?: UserEntity;\n ref?: string;\n };\n each?: JsonValue;\n};\n\ntype CheckpointState =\n | {\n status: 'failed';\n reason: string;\n }\n | {\n status: 'success';\n value: JsonValue;\n };\n\nconst isValidTaskSpec = (taskSpec: TaskSpec): taskSpec is TaskSpecV1beta3 => {\n return taskSpec.apiVersion === 'scaffolder.backstage.io/v1beta3';\n};\n\nconst createStepLogger = ({\n task,\n step,\n rootLogger,\n}: {\n task: TaskContext;\n step: TaskStep;\n rootLogger: winston.Logger;\n}) => {\n const taskLogger = WinstonLogger.create({\n level: process.env.LOG_LEVEL || 'info',\n format: winston.format.combine(\n winston.format.colorize(),\n winston.format.simple(),\n ),\n transports: [new BackstageLoggerTransport(rootLogger, task, step.id)],\n });\n\n taskLogger.addRedactions(Object.values(task.secrets ?? {}));\n\n // This stream logger should be deprecated. We're going to replace it with\n // just using the logger directly, as all those logs get written to step logs\n // using the stepLogStream above.\n // Initially this stream used to be the only way to write to the client logs, but that\n // has changed over time, there's not really a need for this anymore.\n // You can just create a simple wrapper like the below in your action to write to the main logger.\n // This way we also get recactions for free.\n const streamLogger = new PassThrough();\n streamLogger.on('data', async data => {\n const message = data.toString().trim();\n if (message?.length > 1) {\n taskLogger.info(message);\n }\n });\n\n return { taskLogger, streamLogger };\n};\n\nconst isActionAuthorized = createConditionAuthorizer(\n Object.values(scaffolderActionRules),\n);\n\nexport class NunjucksWorkflowRunner implements WorkflowRunner {\n private readonly defaultTemplateFilters: Record<string, TemplateFilter>;\n\n constructor(private readonly options: NunjucksWorkflowRunnerOptions) {\n this.defaultTemplateFilters = createDefaultFilters({\n integrations: this.options.integrations,\n });\n }\n\n private readonly tracker = scaffoldingTracker();\n\n private isSingleTemplateString(input: string) {\n const { parser, nodes } = nunjucks as unknown as {\n parser: {\n parse(\n template: string,\n ctx: object,\n options: nunjucks.ConfigureOptions,\n ): { children: { children?: unknown[] }[] };\n };\n nodes: { TemplateData: Function };\n };\n\n const parsed = parser.parse(\n input,\n {},\n {\n autoescape: false,\n tags: {\n variableStart: '${{',\n variableEnd: '}}',\n },\n },\n );\n\n return (\n parsed.children.length === 1 &&\n !(parsed.children[0]?.children?.[0] instanceof nodes.TemplateData)\n );\n }\n\n private render<T>(\n input: T,\n context: TemplateContext,\n renderTemplate: SecureTemplateRenderer,\n ): T {\n return JSON.parse(JSON.stringify(input), (_key, value) => {\n try {\n if (typeof value === 'string') {\n try {\n if (this.isSingleTemplateString(value)) {\n // Lets convert ${{ parameters.bob }} to ${{ (parameters.bob) | dump }} so we can keep the input type\n const wrappedDumped = value.replace(\n /\\${{(.+)}}/g,\n '${{ ( $1 ) | dump }}',\n );\n\n // Run the templating\n const templated = renderTemplate(wrappedDumped, context);\n\n // If there's an empty string returned, then it's undefined\n if (templated === '') {\n return undefined;\n }\n\n // Reparse the dumped string\n return JSON.parse(templated);\n }\n } catch (ex) {\n this.options.logger.error(\n `Failed to parse template string: ${value} with error ${ex.message}`,\n );\n }\n\n // Fallback to default behaviour\n const templated = renderTemplate(value, context);\n\n if (templated === '') {\n return undefined;\n }\n\n return templated;\n }\n } catch {\n return value;\n }\n return value;\n });\n }\n\n async executeStep(\n task: TaskContext,\n step: TaskStep,\n context: TemplateContext,\n renderTemplate: (template: string, values: unknown) => string,\n taskTrack: TaskTrackType,\n workspacePath: string,\n decision: PolicyDecision,\n ) {\n const stepTrack = await this.tracker.stepStart(task, step);\n\n if (task.cancelSignal.aborted) {\n throw new Error(`Step ${step.name} has been cancelled.`);\n }\n\n try {\n if (\n step.if === false ||\n (typeof step.if === 'string' &&\n !isTruthy(this.render(step.if, context, renderTemplate)))\n ) {\n await stepTrack.skipFalsy();\n return;\n }\n const action: TemplateAction<JsonObject> =\n this.options.actionRegistry.get(step.action);\n const { taskLogger, streamLogger } = createStepLogger({\n task,\n step,\n rootLogger: this.options.logger,\n });\n\n if (task.isDryRun) {\n const redactedSecrets = Object.fromEntries(\n Object.entries(task.secrets ?? {}).map(secret => [secret[0], '***']),\n );\n const debugInput =\n (step.input &&\n this.render(\n step.input,\n {\n ...context,\n secrets: redactedSecrets,\n },\n renderTemplate,\n )) ??\n {};\n taskLogger.info(\n `Running ${\n action.id\n } in dry-run mode with inputs (secrets redacted): ${JSON.stringify(\n debugInput,\n undefined,\n 2,\n )}`,\n );\n if (!action.supportsDryRun) {\n await taskTrack.skipDryRun(step, action);\n const outputSchema = action.schema?.output;\n if (outputSchema) {\n context.steps[step.id] = {\n output: generateExampleOutput(outputSchema) as {\n [name in string]: JsonValue;\n },\n };\n } else {\n context.steps[step.id] = { output: {} };\n }\n return;\n }\n }\n const iterations = (\n step.each\n ? Object.entries(this.render(step.each, context, renderTemplate)).map(\n ([key, value]) => ({\n each: { key, value },\n }),\n )\n : [{}]\n ).map(i => ({\n ...i,\n // Secrets are only passed when templating the input to actions for security reasons\n input: step.input\n ? this.render(\n step.input,\n { ...context, secrets: task.secrets ?? {}, ...i },\n renderTemplate,\n )\n : {},\n }));\n for (const iteration of iterations) {\n const actionId = `${action.id}${\n iteration.each ? `[${iteration.each.key}]` : ''\n }`;\n\n if (action.schema?.input) {\n const validateResult = validateJsonSchema(\n iteration.input,\n action.schema.input,\n );\n if (!validateResult.valid) {\n const errors = validateResult.errors.join(', ');\n throw new InputError(\n `Invalid input passed to action ${actionId}, ${errors}`,\n );\n }\n }\n if (\n !isActionAuthorized(decision, {\n action: action.id,\n input: iteration.input,\n })\n ) {\n throw new NotAllowedError(\n `Unauthorized action: ${actionId}. The action is not allowed. Input: ${JSON.stringify(\n iteration.input,\n null,\n 2,\n )}`,\n );\n }\n }\n const tmpDirs = new Array<string>();\n const stepOutput: { [outputName: string]: JsonValue } = {};\n const prevTaskState = await task.getTaskState?.();\n\n for (const iteration of iterations) {\n if (iteration.each) {\n taskLogger.info(\n `Running step each: ${JSON.stringify(\n iteration.each,\n (k, v) => (k ? v.toString() : v),\n 0,\n )}`,\n );\n }\n await action.handler({\n input: iteration.input,\n secrets: task.secrets ?? {},\n // TODO(blam): move to LoggerService and away from Winston\n logger: loggerToWinstonLogger(taskLogger),\n logStream: streamLogger,\n workspacePath,\n async checkpoint<U extends JsonValue>(\n keySuffix: string,\n fn: () => Promise<U>,\n ) {\n const key = `v1.task.checkpoint.${step.id}.${keySuffix}`;\n try {\n let prevValue: U | undefined;\n if (prevTaskState) {\n const prevState = (\n prevTaskState.state?.checkpoints as {\n [key: string]: CheckpointState;\n }\n )?.[key];\n if (prevState && prevState.status === 'success') {\n prevValue = prevState.value as U;\n }\n }\n\n const value = prevValue ? prevValue : await fn();\n\n if (!prevValue) {\n task.updateCheckpoint?.({\n key,\n status: 'success',\n value,\n });\n }\n return value;\n } catch (err) {\n task.updateCheckpoint?.({\n key,\n status: 'failed',\n reason: stringifyError(err),\n });\n throw err;\n } finally {\n await task.serializeWorkspace?.({ path: workspacePath });\n }\n },\n createTemporaryDirectory: async () => {\n const tmpDir = await fs.mkdtemp(\n `${workspacePath}_step-${step.id}-`,\n );\n tmpDirs.push(tmpDir);\n return tmpDir;\n },\n output(name: string, value: JsonValue) {\n if (step.each) {\n stepOutput[name] = stepOutput[name] || [];\n (stepOutput[name] as JsonArray).push(value);\n } else {\n stepOutput[name] = value;\n }\n },\n templateInfo: task.spec.templateInfo,\n user: task.spec.user,\n isDryRun: task.isDryRun,\n signal: task.cancelSignal,\n getInitiatorCredentials: () => task.getInitiatorCredentials(),\n });\n }\n\n // Remove all temporary directories that were created when executing the action\n for (const tmpDir of tmpDirs) {\n await fs.remove(tmpDir);\n }\n\n context.steps[step.id] = { output: stepOutput };\n\n if (task.cancelSignal.aborted) {\n throw new Error(`Step ${step.name} has been cancelled.`);\n }\n\n await stepTrack.markSuccessful();\n } catch (err) {\n await taskTrack.markFailed(step, err);\n await stepTrack.markFailed();\n throw err;\n } finally {\n await task.serializeWorkspace?.({ path: workspacePath });\n }\n }\n\n async execute(task: TaskContext): Promise<WorkflowResponse> {\n if (!isValidTaskSpec(task.spec)) {\n throw new InputError(\n 'Wrong template version executed with the workflow engine',\n );\n }\n const taskId = await task.getWorkspaceName();\n\n const workspacePath = path.join(this.options.workingDirectory, taskId);\n\n const { additionalTemplateFilters, additionalTemplateGlobals } =\n this.options;\n\n const renderTemplate = await SecureTemplater.loadRenderer({\n templateFilters: {\n ...this.defaultTemplateFilters,\n ...additionalTemplateFilters,\n },\n templateGlobals: additionalTemplateGlobals,\n });\n\n try {\n await task.rehydrateWorkspace?.({ taskId, targetPath: workspacePath });\n\n const taskTrack = await this.tracker.taskStart(task);\n await fs.ensureDir(workspacePath);\n\n const context: TemplateContext = {\n parameters: task.spec.parameters,\n steps: {},\n user: task.spec.user,\n };\n\n const [decision]: PolicyDecision[] =\n this.options.permissions && task.spec.steps.length\n ? await this.options.permissions.authorizeConditional(\n [{ permission: actionExecutePermission }],\n { credentials: await task.getInitiatorCredentials() },\n )\n : [{ result: AuthorizeResult.ALLOW }];\n\n for (const step of task.spec.steps) {\n await this.executeStep(\n task,\n step,\n context,\n renderTemplate,\n taskTrack,\n workspacePath,\n decision,\n );\n }\n\n const output = this.render(task.spec.output, context, renderTemplate);\n await taskTrack.markSuccessful();\n await task.cleanWorkspace?.();\n\n return { output };\n } finally {\n if (workspacePath) {\n await fs.remove(workspacePath);\n }\n }\n }\n}\n\nfunction scaffoldingTracker() {\n // prom-client metrics are deprecated in favour of OpenTelemetry metrics.\n const promTaskCount = createCounterMetric({\n name: 'scaffolder_task_count',\n help: 'Count of task runs',\n labelNames: ['template', 'user', 'result'],\n });\n const promTaskDuration = createHistogramMetric({\n name: 'scaffolder_task_duration',\n help: 'Duration of a task run',\n labelNames: ['template', 'result'],\n });\n const promtStepCount = createCounterMetric({\n name: 'scaffolder_step_count',\n help: 'Count of step runs',\n labelNames: ['template', 'step', 'result'],\n });\n const promStepDuration = createHistogramMetric({\n name: 'scaffolder_step_duration',\n help: 'Duration of a step runs',\n labelNames: ['template', 'step', 'result'],\n });\n\n const meter = metrics.getMeter('default');\n const taskCount = meter.createCounter('scaffolder.task.count', {\n description: 'Count of task runs',\n });\n\n const taskDuration = meter.createHistogram('scaffolder.task.duration', {\n description: 'Duration of a task run',\n unit: 'seconds',\n });\n\n const stepCount = meter.createCounter('scaffolder.step.count', {\n description: 'Count of step runs',\n });\n\n const stepDuration = meter.createHistogram('scaffolder.step.duration', {\n description: 'Duration of a step runs',\n unit: 'seconds',\n });\n\n async function taskStart(task: TaskContext) {\n await task.emitLog(`Starting up task with ${task.spec.steps.length} steps`);\n const template = task.spec.templateInfo?.entityRef || '';\n const user = task.spec.user?.ref || '';\n\n const startTime = process.hrtime();\n const taskTimer = promTaskDuration.startTimer({\n template,\n });\n\n function endTime() {\n const delta = process.hrtime(startTime);\n return delta[0] + delta[1] / 1e9;\n }\n\n async function skipDryRun(\n step: TaskStep,\n action: TemplateAction<JsonObject>,\n ) {\n task.emitLog(`Skipping because ${action.id} does not support dry-run`, {\n stepId: step.id,\n status: 'skipped',\n });\n }\n\n async function markSuccessful() {\n promTaskCount.inc({\n template,\n user,\n result: 'ok',\n });\n taskTimer({ result: 'ok' });\n\n taskCount.add(1, { template, user, result: 'ok' });\n taskDuration.record(endTime(), {\n result: 'ok',\n });\n }\n\n async function markFailed(step: TaskStep, err: Error) {\n await task.emitLog(String(err.stack), {\n stepId: step.id,\n status: 'failed',\n });\n promTaskCount.inc({\n template,\n user,\n result: 'failed',\n });\n taskTimer({ result: 'failed' });\n\n taskCount.add(1, { template, user, result: 'failed' });\n taskDuration.record(endTime(), {\n result: 'failed',\n });\n }\n\n async function markCancelled(step: TaskStep) {\n await task.emitLog(`Step ${step.id} has been cancelled.`, {\n stepId: step.id,\n status: 'cancelled',\n });\n promTaskCount.inc({\n template,\n user,\n result: 'cancelled',\n });\n taskTimer({ result: 'cancelled' });\n\n taskCount.add(1, { template, user, result: 'cancelled' });\n taskDuration.record(endTime(), {\n result: 'cancelled',\n });\n }\n\n return {\n skipDryRun,\n markCancelled,\n markSuccessful,\n markFailed,\n };\n }\n\n async function stepStart(task: TaskContext, step: TaskStep) {\n await task.emitLog(`Beginning step ${step.name}`, {\n stepId: step.id,\n status: 'processing',\n });\n const template = task.spec.templateInfo?.entityRef || '';\n\n const startTime = process.hrtime();\n const stepTimer = promStepDuration.startTimer({\n template,\n step: step.name,\n });\n\n function endTime() {\n const delta = process.hrtime(startTime);\n return delta[0] + delta[1] / 1e9;\n }\n\n async function markSuccessful() {\n await task.emitLog(`Finished step ${step.name}`, {\n stepId: step.id,\n status: 'completed',\n });\n promtStepCount.inc({\n template,\n step: step.name,\n result: 'ok',\n });\n stepTimer({ result: 'ok' });\n\n stepCount.add(1, { template, step: step.name, result: 'ok' });\n stepDuration.record(endTime(), {\n result: 'ok',\n });\n }\n\n async function markCancelled() {\n promtStepCount.inc({\n template,\n step: step.name,\n result: 'cancelled',\n });\n stepTimer({ result: 'cancelled' });\n\n stepCount.add(1, { template, step: step.name, result: 'cancelled' });\n stepDuration.record(endTime(), {\n result: 'cancelled',\n });\n }\n\n async function markFailed() {\n promtStepCount.inc({\n template,\n step: step.name,\n result: 'failed',\n });\n stepTimer({ result: 'failed' });\n\n stepCount.add(1, { template, step: step.name, result: 'failed' });\n stepDuration.record(endTime(), {\n result: 'failed',\n });\n }\n\n async function skipFalsy() {\n await task.emitLog(\n `Skipping step ${step.id} because its if condition was false`,\n { stepId: step.id, status: 'skipped' },\n );\n stepTimer({ result: 'skipped' });\n\n stepCount.add(1, { template, step: step.name, result: 'skipped' });\n stepDuration.record(endTime(), {\n result: 'skipped',\n });\n }\n\n return {\n markCancelled,\n markFailed,\n markSuccessful,\n skipFalsy,\n };\n }\n\n return {\n taskStart,\n stepStart,\n };\n}\n"],"names":["WinstonLogger","winston","BackstageLoggerTransport","PassThrough","createConditionAuthorizer","scaffolderActionRules","createDefaultFilters","nunjucks","templated","isTruthy","generateExampleOutput","validateJsonSchema","errors","InputError","NotAllowedError","loggerToWinstonLogger","stringifyError","fs","path","SecureTemplater","actionExecutePermission","AuthorizeResult","createCounterMetric","createHistogramMetric","metrics"],"mappings":"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"}
1
+ {"version":3,"file":"NunjucksWorkflowRunner.cjs.js","sources":["../../../src/scaffolder/tasks/NunjucksWorkflowRunner.ts"],"sourcesContent":["/*\n * Copyright 2021 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 { ScmIntegrations } from '@backstage/integration';\nimport { TaskTrackType, WorkflowResponse, WorkflowRunner } from './types';\nimport * as winston from 'winston';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport nunjucks from 'nunjucks';\nimport { JsonArray, JsonObject, JsonValue } from '@backstage/types';\nimport { InputError, NotAllowedError, stringifyError } from '@backstage/errors';\nimport { PassThrough } from 'stream';\nimport { generateExampleOutput, isTruthy } from './helper';\nimport { validate as validateJsonSchema } from 'jsonschema';\nimport { TemplateActionRegistry } from '../actions';\nimport { metrics } from '@opentelemetry/api';\nimport {\n SecureTemplater,\n SecureTemplateRenderer,\n} from '../../lib/templating/SecureTemplater';\nimport {\n TaskRecovery,\n TaskSpec,\n TaskSpecV1beta3,\n TaskStep,\n} from '@backstage/plugin-scaffolder-common';\n\nimport {\n TemplateAction,\n TemplateFilter,\n TemplateGlobal,\n TaskContext,\n} from '@backstage/plugin-scaffolder-node';\nimport { createConditionAuthorizer } from '@backstage/plugin-permission-node';\nimport { UserEntity } from '@backstage/catalog-model';\nimport { createCounterMetric, createHistogramMetric } from '../../util/metrics';\nimport { createDefaultFilters } from '../../lib/templating/filters';\nimport {\n AuthorizeResult,\n PolicyDecision,\n} from '@backstage/plugin-permission-common';\nimport { scaffolderActionRules } from '../../service/rules';\nimport { actionExecutePermission } from '@backstage/plugin-scaffolder-common/alpha';\nimport { PermissionsService } from '@backstage/backend-plugin-api';\nimport { loggerToWinstonLogger } from '@backstage/backend-common';\nimport { BackstageLoggerTransport, WinstonLogger } from './logger';\n\ntype NunjucksWorkflowRunnerOptions = {\n workingDirectory: string;\n actionRegistry: TemplateActionRegistry;\n integrations: ScmIntegrations;\n logger: winston.Logger;\n additionalTemplateFilters?: Record<string, TemplateFilter>;\n additionalTemplateGlobals?: Record<string, TemplateGlobal>;\n permissions?: PermissionsService;\n};\n\ntype TemplateContext = {\n parameters: JsonObject;\n EXPERIMENTAL_recovery?: TaskRecovery;\n steps: {\n [stepName: string]: { output: { [outputName: string]: JsonValue } };\n };\n secrets?: Record<string, string>;\n user?: {\n entity?: UserEntity;\n ref?: string;\n };\n each?: JsonValue;\n};\n\ntype CheckpointState =\n | {\n status: 'failed';\n reason: string;\n }\n | {\n status: 'success';\n value: JsonValue;\n };\n\nconst isValidTaskSpec = (taskSpec: TaskSpec): taskSpec is TaskSpecV1beta3 => {\n return taskSpec.apiVersion === 'scaffolder.backstage.io/v1beta3';\n};\n\nconst createStepLogger = ({\n task,\n step,\n rootLogger,\n}: {\n task: TaskContext;\n step: TaskStep;\n rootLogger: winston.Logger;\n}) => {\n const taskLogger = WinstonLogger.create({\n level: process.env.LOG_LEVEL || 'info',\n format: winston.format.combine(\n winston.format.colorize(),\n winston.format.simple(),\n ),\n transports: [new BackstageLoggerTransport(rootLogger, task, step.id)],\n });\n\n taskLogger.addRedactions(Object.values(task.secrets ?? {}));\n\n // This stream logger should be deprecated. We're going to replace it with\n // just using the logger directly, as all those logs get written to step logs\n // using the stepLogStream above.\n // Initially this stream used to be the only way to write to the client logs, but that\n // has changed over time, there's not really a need for this anymore.\n // You can just create a simple wrapper like the below in your action to write to the main logger.\n // This way we also get recactions for free.\n const streamLogger = new PassThrough();\n streamLogger.on('data', async data => {\n const message = data.toString().trim();\n if (message?.length > 1) {\n taskLogger.info(message);\n }\n });\n\n return { taskLogger, streamLogger };\n};\n\nconst isActionAuthorized = createConditionAuthorizer(\n Object.values(scaffolderActionRules),\n);\n\nexport class NunjucksWorkflowRunner implements WorkflowRunner {\n private readonly defaultTemplateFilters: Record<string, TemplateFilter>;\n\n constructor(private readonly options: NunjucksWorkflowRunnerOptions) {\n this.defaultTemplateFilters = createDefaultFilters({\n integrations: this.options.integrations,\n });\n }\n\n private readonly tracker = scaffoldingTracker();\n\n private isSingleTemplateString(input: string) {\n const { parser, nodes } = nunjucks as unknown as {\n parser: {\n parse(\n template: string,\n ctx: object,\n options: nunjucks.ConfigureOptions,\n ): { children: { children?: unknown[] }[] };\n };\n nodes: { TemplateData: Function };\n };\n\n const parsed = parser.parse(\n input,\n {},\n {\n autoescape: false,\n tags: {\n variableStart: '${{',\n variableEnd: '}}',\n },\n },\n );\n\n return (\n parsed.children.length === 1 &&\n !(parsed.children[0]?.children?.[0] instanceof nodes.TemplateData)\n );\n }\n\n private render<T>(\n input: T,\n context: TemplateContext,\n renderTemplate: SecureTemplateRenderer,\n ): T {\n return JSON.parse(JSON.stringify(input), (_key, value) => {\n try {\n if (typeof value === 'string') {\n try {\n if (this.isSingleTemplateString(value)) {\n // Lets convert ${{ parameters.bob }} to ${{ (parameters.bob) | dump }} so we can keep the input type\n const wrappedDumped = value.replace(\n /\\${{(.+)}}/g,\n '${{ ( $1 ) | dump }}',\n );\n\n // Run the templating\n const templated = renderTemplate(wrappedDumped, context);\n\n // If there's an empty string returned, then it's undefined\n if (templated === '') {\n return undefined;\n }\n\n // Reparse the dumped string\n return JSON.parse(templated);\n }\n } catch (ex) {\n this.options.logger.error(\n `Failed to parse template string: ${value} with error ${ex.message}`,\n );\n }\n\n // Fallback to default behaviour\n const templated = renderTemplate(value, context);\n\n if (templated === '') {\n return undefined;\n }\n\n return templated;\n }\n } catch {\n return value;\n }\n return value;\n });\n }\n\n async executeStep(\n task: TaskContext,\n step: TaskStep,\n context: TemplateContext,\n renderTemplate: (template: string, values: unknown) => string,\n taskTrack: TaskTrackType,\n workspacePath: string,\n decision: PolicyDecision,\n ) {\n const stepTrack = await this.tracker.stepStart(task, step);\n\n if (task.cancelSignal.aborted) {\n throw new Error(`Step ${step.name} has been cancelled.`);\n }\n\n try {\n if (\n step.if === false ||\n (typeof step.if === 'string' &&\n !isTruthy(this.render(step.if, context, renderTemplate)))\n ) {\n await stepTrack.skipFalsy();\n return;\n }\n const action: TemplateAction<JsonObject> =\n this.options.actionRegistry.get(step.action);\n const { taskLogger, streamLogger } = createStepLogger({\n task,\n step,\n rootLogger: this.options.logger,\n });\n\n if (task.isDryRun) {\n const redactedSecrets = Object.fromEntries(\n Object.entries(task.secrets ?? {}).map(secret => [secret[0], '***']),\n );\n const debugInput =\n (step.input &&\n this.render(\n step.input,\n {\n ...context,\n secrets: redactedSecrets,\n },\n renderTemplate,\n )) ??\n {};\n taskLogger.info(\n `Running ${\n action.id\n } in dry-run mode with inputs (secrets redacted): ${JSON.stringify(\n debugInput,\n undefined,\n 2,\n )}`,\n );\n if (!action.supportsDryRun) {\n await taskTrack.skipDryRun(step, action);\n const outputSchema = action.schema?.output;\n if (outputSchema) {\n context.steps[step.id] = {\n output: generateExampleOutput(outputSchema) as {\n [name in string]: JsonValue;\n },\n };\n } else {\n context.steps[step.id] = { output: {} };\n }\n return;\n }\n }\n const iterations = (\n step.each\n ? Object.entries(this.render(step.each, context, renderTemplate)).map(\n ([key, value]) => ({\n each: { key, value },\n }),\n )\n : [{}]\n ).map(i => ({\n ...i,\n // Secrets are only passed when templating the input to actions for security reasons\n input: step.input\n ? this.render(\n step.input,\n { ...context, secrets: task.secrets ?? {}, ...i },\n renderTemplate,\n )\n : {},\n }));\n for (const iteration of iterations) {\n const actionId = `${action.id}${\n iteration.each ? `[${iteration.each.key}]` : ''\n }`;\n\n if (action.schema?.input) {\n const validateResult = validateJsonSchema(\n iteration.input,\n action.schema.input,\n );\n if (!validateResult.valid) {\n const errors = validateResult.errors.join(', ');\n throw new InputError(\n `Invalid input passed to action ${actionId}, ${errors}`,\n );\n }\n }\n if (\n !isActionAuthorized(decision, {\n action: action.id,\n input: iteration.input,\n })\n ) {\n throw new NotAllowedError(\n `Unauthorized action: ${actionId}. The action is not allowed. Input: ${JSON.stringify(\n iteration.input,\n null,\n 2,\n )}`,\n );\n }\n }\n const tmpDirs = new Array<string>();\n const stepOutput: { [outputName: string]: JsonValue } = {};\n const prevTaskState = await task.getTaskState?.();\n\n for (const iteration of iterations) {\n if (iteration.each) {\n taskLogger.info(\n `Running step each: ${JSON.stringify(\n iteration.each,\n (k, v) => (k ? v.toString() : v),\n 0,\n )}`,\n );\n }\n\n await action.handler({\n input: iteration.input,\n secrets: task.secrets ?? {},\n // TODO(blam): move to LoggerService and away from Winston\n logger: loggerToWinstonLogger(taskLogger),\n logStream: streamLogger,\n workspacePath,\n async checkpoint<T extends JsonValue | void>(opts: {\n key?: string;\n fn: () => Promise<T> | T;\n }) {\n const { key: checkpointKey, fn } = opts;\n const key = `v1.task.checkpoint.${step.id}.${checkpointKey}`;\n\n try {\n let prevValue: T | undefined;\n\n if (prevTaskState) {\n const prevState = (\n prevTaskState.state?.checkpoints as {\n [key: string]: CheckpointState;\n }\n )?.[key];\n\n if (prevState && prevState.status === 'success') {\n prevValue = prevState.value as T;\n }\n }\n\n const value = prevValue ? prevValue : await fn();\n\n if (!prevValue) {\n task.updateCheckpoint?.({\n key,\n status: 'success',\n value: value ?? {},\n });\n }\n return value;\n } catch (err) {\n task.updateCheckpoint?.({\n key,\n status: 'failed',\n reason: stringifyError(err),\n });\n throw err;\n } finally {\n await task.serializeWorkspace?.({ path: workspacePath });\n }\n },\n createTemporaryDirectory: async () => {\n const tmpDir = await fs.mkdtemp(\n `${workspacePath}_step-${step.id}-`,\n );\n tmpDirs.push(tmpDir);\n return tmpDir;\n },\n output(name: string, value: JsonValue) {\n if (step.each) {\n stepOutput[name] = stepOutput[name] || [];\n (stepOutput[name] as JsonArray).push(value);\n } else {\n stepOutput[name] = value;\n }\n },\n templateInfo: task.spec.templateInfo,\n user: task.spec.user,\n isDryRun: task.isDryRun,\n signal: task.cancelSignal,\n getInitiatorCredentials: () => task.getInitiatorCredentials(),\n });\n }\n\n // Remove all temporary directories that were created when executing the action\n for (const tmpDir of tmpDirs) {\n await fs.remove(tmpDir);\n }\n\n context.steps[step.id] = { output: stepOutput };\n\n if (task.cancelSignal.aborted) {\n throw new Error(`Step ${step.name} has been cancelled.`);\n }\n\n await stepTrack.markSuccessful();\n } catch (err) {\n await taskTrack.markFailed(step, err);\n await stepTrack.markFailed();\n throw err;\n } finally {\n await task.serializeWorkspace?.({ path: workspacePath });\n }\n }\n\n async execute(task: TaskContext): Promise<WorkflowResponse> {\n if (!isValidTaskSpec(task.spec)) {\n throw new InputError(\n 'Wrong template version executed with the workflow engine',\n );\n }\n const taskId = await task.getWorkspaceName();\n\n const workspacePath = path.join(this.options.workingDirectory, taskId);\n\n const { additionalTemplateFilters, additionalTemplateGlobals } =\n this.options;\n\n const renderTemplate = await SecureTemplater.loadRenderer({\n templateFilters: {\n ...this.defaultTemplateFilters,\n ...additionalTemplateFilters,\n },\n templateGlobals: additionalTemplateGlobals,\n });\n\n try {\n await task.rehydrateWorkspace?.({ taskId, targetPath: workspacePath });\n\n const taskTrack = await this.tracker.taskStart(task);\n await fs.ensureDir(workspacePath);\n\n const context: TemplateContext = {\n parameters: task.spec.parameters,\n steps: {},\n user: task.spec.user,\n };\n\n const [decision]: PolicyDecision[] =\n this.options.permissions && task.spec.steps.length\n ? await this.options.permissions.authorizeConditional(\n [{ permission: actionExecutePermission }],\n { credentials: await task.getInitiatorCredentials() },\n )\n : [{ result: AuthorizeResult.ALLOW }];\n\n for (const step of task.spec.steps) {\n await this.executeStep(\n task,\n step,\n context,\n renderTemplate,\n taskTrack,\n workspacePath,\n decision,\n );\n }\n\n const output = this.render(task.spec.output, context, renderTemplate);\n await taskTrack.markSuccessful();\n await task.cleanWorkspace?.();\n\n return { output };\n } finally {\n if (workspacePath) {\n await fs.remove(workspacePath);\n }\n }\n }\n}\n\nfunction scaffoldingTracker() {\n // prom-client metrics are deprecated in favour of OpenTelemetry metrics.\n const promTaskCount = createCounterMetric({\n name: 'scaffolder_task_count',\n help: 'Count of task runs',\n labelNames: ['template', 'user', 'result'],\n });\n const promTaskDuration = createHistogramMetric({\n name: 'scaffolder_task_duration',\n help: 'Duration of a task run',\n labelNames: ['template', 'result'],\n });\n const promtStepCount = createCounterMetric({\n name: 'scaffolder_step_count',\n help: 'Count of step runs',\n labelNames: ['template', 'step', 'result'],\n });\n const promStepDuration = createHistogramMetric({\n name: 'scaffolder_step_duration',\n help: 'Duration of a step runs',\n labelNames: ['template', 'step', 'result'],\n });\n\n const meter = metrics.getMeter('default');\n const taskCount = meter.createCounter('scaffolder.task.count', {\n description: 'Count of task runs',\n });\n\n const taskDuration = meter.createHistogram('scaffolder.task.duration', {\n description: 'Duration of a task run',\n unit: 'seconds',\n });\n\n const stepCount = meter.createCounter('scaffolder.step.count', {\n description: 'Count of step runs',\n });\n\n const stepDuration = meter.createHistogram('scaffolder.step.duration', {\n description: 'Duration of a step runs',\n unit: 'seconds',\n });\n\n async function taskStart(task: TaskContext) {\n await task.emitLog(`Starting up task with ${task.spec.steps.length} steps`);\n const template = task.spec.templateInfo?.entityRef || '';\n const user = task.spec.user?.ref || '';\n\n const startTime = process.hrtime();\n const taskTimer = promTaskDuration.startTimer({\n template,\n });\n\n function endTime() {\n const delta = process.hrtime(startTime);\n return delta[0] + delta[1] / 1e9;\n }\n\n async function skipDryRun(\n step: TaskStep,\n action: TemplateAction<JsonObject>,\n ) {\n task.emitLog(`Skipping because ${action.id} does not support dry-run`, {\n stepId: step.id,\n status: 'skipped',\n });\n }\n\n async function markSuccessful() {\n promTaskCount.inc({\n template,\n user,\n result: 'ok',\n });\n taskTimer({ result: 'ok' });\n\n taskCount.add(1, { template, user, result: 'ok' });\n taskDuration.record(endTime(), {\n result: 'ok',\n });\n }\n\n async function markFailed(step: TaskStep, err: Error) {\n await task.emitLog(String(err.stack), {\n stepId: step.id,\n status: 'failed',\n });\n promTaskCount.inc({\n template,\n user,\n result: 'failed',\n });\n taskTimer({ result: 'failed' });\n\n taskCount.add(1, { template, user, result: 'failed' });\n taskDuration.record(endTime(), {\n result: 'failed',\n });\n }\n\n async function markCancelled(step: TaskStep) {\n await task.emitLog(`Step ${step.id} has been cancelled.`, {\n stepId: step.id,\n status: 'cancelled',\n });\n promTaskCount.inc({\n template,\n user,\n result: 'cancelled',\n });\n taskTimer({ result: 'cancelled' });\n\n taskCount.add(1, { template, user, result: 'cancelled' });\n taskDuration.record(endTime(), {\n result: 'cancelled',\n });\n }\n\n return {\n skipDryRun,\n markCancelled,\n markSuccessful,\n markFailed,\n };\n }\n\n async function stepStart(task: TaskContext, step: TaskStep) {\n await task.emitLog(`Beginning step ${step.name}`, {\n stepId: step.id,\n status: 'processing',\n });\n const template = task.spec.templateInfo?.entityRef || '';\n\n const startTime = process.hrtime();\n const stepTimer = promStepDuration.startTimer({\n template,\n step: step.name,\n });\n\n function endTime() {\n const delta = process.hrtime(startTime);\n return delta[0] + delta[1] / 1e9;\n }\n\n async function markSuccessful() {\n await task.emitLog(`Finished step ${step.name}`, {\n stepId: step.id,\n status: 'completed',\n });\n promtStepCount.inc({\n template,\n step: step.name,\n result: 'ok',\n });\n stepTimer({ result: 'ok' });\n\n stepCount.add(1, { template, step: step.name, result: 'ok' });\n stepDuration.record(endTime(), {\n result: 'ok',\n });\n }\n\n async function markCancelled() {\n promtStepCount.inc({\n template,\n step: step.name,\n result: 'cancelled',\n });\n stepTimer({ result: 'cancelled' });\n\n stepCount.add(1, { template, step: step.name, result: 'cancelled' });\n stepDuration.record(endTime(), {\n result: 'cancelled',\n });\n }\n\n async function markFailed() {\n promtStepCount.inc({\n template,\n step: step.name,\n result: 'failed',\n });\n stepTimer({ result: 'failed' });\n\n stepCount.add(1, { template, step: step.name, result: 'failed' });\n stepDuration.record(endTime(), {\n result: 'failed',\n });\n }\n\n async function skipFalsy() {\n await task.emitLog(\n `Skipping step ${step.id} because its if condition was false`,\n { stepId: step.id, status: 'skipped' },\n );\n stepTimer({ result: 'skipped' });\n\n stepCount.add(1, { template, step: step.name, result: 'skipped' });\n stepDuration.record(endTime(), {\n result: 'skipped',\n });\n }\n\n return {\n markCancelled,\n markFailed,\n markSuccessful,\n skipFalsy,\n };\n }\n\n return {\n taskStart,\n stepStart,\n };\n}\n"],"names":["WinstonLogger","winston","BackstageLoggerTransport","PassThrough","createConditionAuthorizer","scaffolderActionRules","createDefaultFilters","nunjucks","templated","isTruthy","generateExampleOutput","validateJsonSchema","errors","InputError","NotAllowedError","loggerToWinstonLogger","stringifyError","fs","path","SecureTemplater","actionExecutePermission","AuthorizeResult","createCounterMetric","createHistogramMetric","metrics"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ var types = require('@backstage/types');
3
4
  var ObservableImpl = require('zen-observable');
4
5
  var helper = require('./helper.cjs.js');
5
6
  var WorkspaceService = require('./WorkspaceService.cjs.js');
@@ -127,14 +128,6 @@ class TaskManager {
127
128
  return this.auth.getNoneCredentials();
128
129
  }
129
130
  }
130
- function defer() {
131
- let resolve = () => {
132
- };
133
- const promise = new Promise((_resolve) => {
134
- resolve = _resolve;
135
- });
136
- return { promise, resolve };
137
- }
138
131
  class StorageTaskBroker {
139
132
  constructor(storage, logger, config, auth, additionalWorkspaceProviders) {
140
133
  this.storage = storage;
@@ -151,7 +144,7 @@ class StorageTaskBroker {
151
144
  }
152
145
  return await this.storage.list(options ?? {});
153
146
  }
154
- deferredDispatch = defer();
147
+ deferredDispatch = types.createDeferred();
155
148
  async registerCancellable(taskId, abortController) {
156
149
  let shouldUnsubscribe = false;
157
150
  const subscription = this.event$({ taskId, after: void 0 }).subscribe({
@@ -289,11 +282,11 @@ class StorageTaskBroker {
289
282
  );
290
283
  }
291
284
  waitForDispatch() {
292
- return this.deferredDispatch.promise;
285
+ return this.deferredDispatch;
293
286
  }
294
287
  signalDispatch() {
295
288
  this.deferredDispatch.resolve();
296
- this.deferredDispatch = defer();
289
+ this.deferredDispatch = types.createDeferred();
297
290
  }
298
291
  async cancel(taskId) {
299
292
  const { events } = await this.storage.listEvents({ taskId });
@@ -1 +1 @@
1
- {"version":3,"file":"StorageTaskBroker.cjs.js","sources":["../../../src/scaffolder/tasks/StorageTaskBroker.ts"],"sourcesContent":["/*\n * Copyright 2021 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 { Config } from '@backstage/config';\nimport { TaskSpec } from '@backstage/plugin-scaffolder-common';\nimport { JsonObject, JsonValue, Observable } from '@backstage/types';\nimport { Logger } from 'winston';\nimport ObservableImpl from 'zen-observable';\nimport {\n SerializedTask,\n SerializedTaskEvent,\n TaskBroker,\n TaskBrokerDispatchOptions,\n TaskCompletionState,\n TaskContext,\n TaskSecrets,\n TaskStatus,\n} from '@backstage/plugin-scaffolder-node';\nimport { InternalTaskSecrets, TaskStore } from './types';\nimport { readDuration } from './helper';\nimport {\n AuthService,\n BackstageCredentials,\n} from '@backstage/backend-plugin-api';\nimport { DefaultWorkspaceService, WorkspaceService } from './WorkspaceService';\nimport { WorkspaceProvider } from '@backstage/plugin-scaffolder-node/alpha';\n\ntype TaskState = {\n checkpoints: {\n [key: string]:\n | {\n status: 'failed';\n reason: string;\n }\n | {\n status: 'success';\n value: JsonValue;\n };\n };\n};\n/**\n * TaskManager\n *\n * @public\n */\nexport class TaskManager implements TaskContext {\n private isDone = false;\n\n private heartbeatTimeoutId?: ReturnType<typeof setInterval>;\n\n static create(\n task: CurrentClaimedTask,\n storage: TaskStore,\n abortSignal: AbortSignal,\n logger: Logger,\n auth?: AuthService,\n config?: Config,\n additionalWorkspaceProviders?: Record<string, WorkspaceProvider>,\n ) {\n const workspaceService = DefaultWorkspaceService.create(\n task,\n storage,\n additionalWorkspaceProviders,\n config,\n );\n\n const agent = new TaskManager(\n task,\n storage,\n abortSignal,\n logger,\n workspaceService,\n auth,\n );\n agent.startTimeout();\n return agent;\n }\n\n // Runs heartbeat internally\n private constructor(\n private readonly task: CurrentClaimedTask,\n private readonly storage: TaskStore,\n private readonly signal: AbortSignal,\n private readonly logger: Logger,\n private readonly workspaceService: WorkspaceService,\n private readonly auth?: AuthService,\n ) {}\n\n get spec() {\n return this.task.spec;\n }\n\n get cancelSignal() {\n return this.signal;\n }\n\n get secrets() {\n return this.task.secrets;\n }\n\n get createdBy() {\n return this.task.createdBy;\n }\n\n async getWorkspaceName() {\n return this.task.taskId;\n }\n\n async rehydrateWorkspace?(options: {\n taskId: string;\n targetPath: string;\n }): Promise<void> {\n await this.workspaceService.rehydrateWorkspace(options);\n }\n\n get done() {\n return this.isDone;\n }\n\n async emitLog(message: string, logMetadata?: JsonObject): Promise<void> {\n await this.storage.emitLogEvent({\n taskId: this.task.taskId,\n body: { message, ...logMetadata },\n });\n }\n\n async getTaskState?(): Promise<\n | {\n state?: JsonObject;\n }\n | undefined\n > {\n return this.storage.getTaskState?.({ taskId: this.task.taskId });\n }\n\n async updateCheckpoint?(\n options:\n | {\n key: string;\n status: 'success';\n value: JsonValue;\n }\n | {\n key: string;\n status: 'failed';\n reason: string;\n },\n ): Promise<void> {\n const { key, ...value } = options;\n if (this.task.state) {\n (this.task.state as TaskState).checkpoints[key] = value;\n } else {\n this.task.state = { checkpoints: { [key]: value } };\n }\n await this.storage.saveTaskState?.({\n taskId: this.task.taskId,\n state: this.task.state,\n });\n }\n\n async serializeWorkspace?(options: { path: string }): Promise<void> {\n await this.workspaceService.serializeWorkspace(options);\n }\n\n async cleanWorkspace?(): Promise<void> {\n await this.workspaceService.cleanWorkspace();\n }\n\n async complete(\n result: TaskCompletionState,\n metadata?: JsonObject,\n ): Promise<void> {\n await this.storage.completeTask({\n taskId: this.task.taskId,\n status: result === 'failed' ? 'failed' : 'completed',\n eventBody: {\n message: `Run completed with status: ${result}`,\n ...metadata,\n },\n });\n this.isDone = true;\n if (this.heartbeatTimeoutId) {\n clearTimeout(this.heartbeatTimeoutId);\n }\n }\n\n private startTimeout() {\n this.heartbeatTimeoutId = setTimeout(async () => {\n try {\n await this.storage.heartbeatTask(this.task.taskId);\n this.startTimeout();\n } catch (error) {\n this.isDone = true;\n\n this.logger.error(\n `Heartbeat for task ${this.task.taskId} failed`,\n error,\n );\n }\n }, 1000);\n }\n\n async getInitiatorCredentials(): Promise<BackstageCredentials> {\n const secrets = this.task.secrets as InternalTaskSecrets;\n\n if (secrets && secrets.__initiatorCredentials) {\n return JSON.parse(secrets.__initiatorCredentials);\n }\n if (!this.auth) {\n throw new Error(\n 'Failed to create none credentials in scaffolder task. The TaskManager has not been initialized with an auth service implementation',\n );\n }\n return this.auth.getNoneCredentials();\n }\n}\n\n/**\n * Stores the state of the current claimed task passed to the TaskContext\n *\n * @public\n */\nexport interface CurrentClaimedTask {\n /**\n * The TaskSpec of the current claimed task.\n */\n spec: TaskSpec;\n /**\n * The uuid of the current claimed task.\n */\n taskId: string;\n /**\n * The secrets that are stored with the task.\n */\n secrets?: TaskSecrets;\n /**\n * The state of checkpoints of the task.\n */\n state?: JsonObject;\n /**\n * The creator of the task.\n */\n createdBy?: string;\n /**\n * The workspace of the task.\n */\n workspace?: Promise<Buffer>;\n}\n\nfunction defer() {\n let resolve = () => {};\n const promise = new Promise<void>(_resolve => {\n resolve = _resolve;\n });\n return { promise, resolve };\n}\n\nexport class StorageTaskBroker implements TaskBroker {\n constructor(\n private readonly storage: TaskStore,\n private readonly logger: Logger,\n private readonly config?: Config,\n private readonly auth?: AuthService,\n private readonly additionalWorkspaceProviders?: Record<\n string,\n WorkspaceProvider\n >,\n ) {}\n\n async list(options?: {\n createdBy?: string;\n status?: TaskStatus;\n filters?: {\n createdBy?: string | string[];\n status?: TaskStatus | TaskStatus[];\n };\n pagination?: {\n limit?: number;\n offset?: number;\n };\n order?: { order: 'asc' | 'desc'; field: string }[];\n }): Promise<{ tasks: SerializedTask[]; totalTasks?: number }> {\n if (!this.storage.list) {\n throw new Error(\n 'TaskStore does not implement the list method. Please implement the list method to be able to list tasks',\n );\n }\n return await this.storage.list(options ?? {});\n }\n\n private deferredDispatch = defer();\n\n private async registerCancellable(\n taskId: string,\n abortController: AbortController,\n ) {\n let shouldUnsubscribe = false;\n const subscription = this.event$({ taskId, after: undefined }).subscribe({\n error: _ => {\n subscription.unsubscribe();\n },\n next: ({ events }) => {\n for (const event of events) {\n if (event.type === 'cancelled') {\n abortController.abort();\n shouldUnsubscribe = true;\n }\n\n if (event.type === 'completion' && !event.isTaskRecoverable) {\n shouldUnsubscribe = true;\n }\n }\n if (shouldUnsubscribe) {\n subscription.unsubscribe();\n }\n },\n });\n }\n\n public async recoverTasks(): Promise<void> {\n const enabled =\n (this.config &&\n this.config.getOptionalBoolean(\n 'scaffolder.EXPERIMENTAL_recoverTasks',\n )) ??\n false;\n\n if (enabled) {\n const defaultTimeout = { seconds: 30 };\n const timeout = readDuration(\n this.config,\n 'scaffolder.EXPERIMENTAL_recoverTasksTimeout',\n defaultTimeout,\n );\n const { ids: recoveredTaskIds } = (await this.storage.recoverTasks?.({\n timeout,\n })) ?? { ids: [] };\n if (recoveredTaskIds.length > 0) {\n this.signalDispatch();\n }\n }\n }\n\n /**\n * {@inheritdoc TaskBroker.claim}\n */\n async claim(): Promise<TaskContext> {\n for (;;) {\n const pendingTask = await this.storage.claimTask();\n if (pendingTask) {\n const abortController = new AbortController();\n await this.registerCancellable(pendingTask.id, abortController);\n return TaskManager.create(\n {\n taskId: pendingTask.id,\n spec: pendingTask.spec,\n secrets: pendingTask.secrets,\n createdBy: pendingTask.createdBy,\n state: pendingTask.state,\n },\n this.storage,\n abortController.signal,\n this.logger,\n this.auth,\n this.config,\n this.additionalWorkspaceProviders,\n );\n }\n\n await this.waitForDispatch();\n }\n }\n\n /**\n * {@inheritdoc TaskBroker.dispatch}\n */\n async dispatch(\n options: TaskBrokerDispatchOptions,\n ): Promise<{ taskId: string }> {\n const taskRow = await this.storage.createTask(options);\n this.signalDispatch();\n return {\n taskId: taskRow.taskId,\n };\n }\n\n /**\n * {@inheritdoc TaskBroker.get}\n */\n async get(taskId: string): Promise<SerializedTask> {\n return this.storage.getTask(taskId);\n }\n\n /**\n * {@inheritdoc TaskBroker.event$}\n */\n event$(options: {\n taskId: string;\n after?: number;\n }): Observable<{ events: SerializedTaskEvent[] }> {\n return new ObservableImpl(observer => {\n const { taskId } = options;\n\n let after = options.after;\n let cancelled = false;\n\n (async () => {\n const task = await this.storage.getTask(taskId);\n const isTaskRecoverable =\n task.spec.EXPERIMENTAL_recovery?.EXPERIMENTAL_strategy ===\n 'startOver';\n\n while (!cancelled) {\n const result = await this.storage.listEvents({\n isTaskRecoverable,\n taskId,\n after,\n });\n const { events } = result;\n if (events.length) {\n after = events[events.length - 1].id;\n observer.next(result);\n }\n\n await new Promise(resolve => setTimeout(resolve, 1000));\n }\n })();\n\n return () => {\n cancelled = true;\n };\n });\n }\n\n /**\n * {@inheritdoc TaskBroker.vacuumTasks}\n */\n async vacuumTasks(options: { timeoutS: number }): Promise<void> {\n const { tasks } = await this.storage.listStaleTasks(options);\n await Promise.all(\n tasks.map(async task => {\n try {\n await this.storage.completeTask({\n taskId: task.taskId,\n status: 'failed',\n eventBody: {\n message:\n 'The task was cancelled because the task worker lost connection to the task broker',\n },\n });\n } catch (error) {\n this.logger.warn(`Failed to cancel task '${task.taskId}', ${error}`);\n }\n }),\n );\n }\n\n private waitForDispatch() {\n return this.deferredDispatch.promise;\n }\n\n private signalDispatch() {\n this.deferredDispatch.resolve();\n this.deferredDispatch = defer();\n }\n\n async cancel(taskId: string) {\n const { events } = await this.storage.listEvents({ taskId });\n const currentStepId =\n events.length > 0\n ? events\n .filter(({ body }) => body?.stepId)\n .reduce((prev, curr) => (prev.id > curr.id ? prev : curr)).body\n .stepId\n : 0;\n\n await this.storage.cancelTask?.({\n taskId,\n body: {\n message: `Step ${currentStepId} has been cancelled.`,\n stepId: currentStepId,\n status: 'cancelled',\n },\n });\n }\n\n async retry?(taskId: string): Promise<void> {\n await this.storage.retryTask?.({ taskId });\n this.signalDispatch();\n }\n}\n"],"names":["DefaultWorkspaceService","readDuration","ObservableImpl"],"mappings":"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"}
1
+ {"version":3,"file":"StorageTaskBroker.cjs.js","sources":["../../../src/scaffolder/tasks/StorageTaskBroker.ts"],"sourcesContent":["/*\n * Copyright 2021 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 { Config } from '@backstage/config';\nimport { TaskSpec } from '@backstage/plugin-scaffolder-common';\nimport {\n JsonObject,\n JsonValue,\n Observable,\n createDeferred,\n} from '@backstage/types';\nimport { Logger } from 'winston';\nimport ObservableImpl from 'zen-observable';\nimport {\n SerializedTask,\n SerializedTaskEvent,\n TaskBroker,\n TaskBrokerDispatchOptions,\n TaskCompletionState,\n TaskContext,\n TaskSecrets,\n TaskStatus,\n} from '@backstage/plugin-scaffolder-node';\nimport { InternalTaskSecrets, TaskStore } from './types';\nimport { readDuration } from './helper';\nimport {\n AuthService,\n BackstageCredentials,\n} from '@backstage/backend-plugin-api';\nimport { DefaultWorkspaceService, WorkspaceService } from './WorkspaceService';\nimport { WorkspaceProvider } from '@backstage/plugin-scaffolder-node/alpha';\n\ntype TaskState = {\n checkpoints: {\n [key: string]:\n | {\n status: 'failed';\n reason: string;\n }\n | {\n status: 'success';\n value: JsonValue;\n };\n };\n};\n/**\n * TaskManager\n *\n * @public\n */\nexport class TaskManager implements TaskContext {\n private isDone = false;\n\n private heartbeatTimeoutId?: ReturnType<typeof setInterval>;\n\n static create(\n task: CurrentClaimedTask,\n storage: TaskStore,\n abortSignal: AbortSignal,\n logger: Logger,\n auth?: AuthService,\n config?: Config,\n additionalWorkspaceProviders?: Record<string, WorkspaceProvider>,\n ) {\n const workspaceService = DefaultWorkspaceService.create(\n task,\n storage,\n additionalWorkspaceProviders,\n config,\n );\n\n const agent = new TaskManager(\n task,\n storage,\n abortSignal,\n logger,\n workspaceService,\n auth,\n );\n agent.startTimeout();\n return agent;\n }\n\n // Runs heartbeat internally\n private constructor(\n private readonly task: CurrentClaimedTask,\n private readonly storage: TaskStore,\n private readonly signal: AbortSignal,\n private readonly logger: Logger,\n private readonly workspaceService: WorkspaceService,\n private readonly auth?: AuthService,\n ) {}\n\n get spec() {\n return this.task.spec;\n }\n\n get cancelSignal() {\n return this.signal;\n }\n\n get secrets() {\n return this.task.secrets;\n }\n\n get createdBy() {\n return this.task.createdBy;\n }\n\n async getWorkspaceName() {\n return this.task.taskId;\n }\n\n async rehydrateWorkspace?(options: {\n taskId: string;\n targetPath: string;\n }): Promise<void> {\n await this.workspaceService.rehydrateWorkspace(options);\n }\n\n get done() {\n return this.isDone;\n }\n\n async emitLog(message: string, logMetadata?: JsonObject): Promise<void> {\n await this.storage.emitLogEvent({\n taskId: this.task.taskId,\n body: { message, ...logMetadata },\n });\n }\n\n async getTaskState?(): Promise<\n | {\n state?: JsonObject;\n }\n | undefined\n > {\n return this.storage.getTaskState?.({ taskId: this.task.taskId });\n }\n\n async updateCheckpoint?(\n options:\n | {\n key: string;\n status: 'success';\n value: JsonValue;\n }\n | {\n key: string;\n status: 'failed';\n reason: string;\n },\n ): Promise<void> {\n const { key, ...value } = options;\n if (this.task.state) {\n (this.task.state as TaskState).checkpoints[key] = value;\n } else {\n this.task.state = { checkpoints: { [key]: value } };\n }\n await this.storage.saveTaskState?.({\n taskId: this.task.taskId,\n state: this.task.state,\n });\n }\n\n async serializeWorkspace?(options: { path: string }): Promise<void> {\n await this.workspaceService.serializeWorkspace(options);\n }\n\n async cleanWorkspace?(): Promise<void> {\n await this.workspaceService.cleanWorkspace();\n }\n\n async complete(\n result: TaskCompletionState,\n metadata?: JsonObject,\n ): Promise<void> {\n await this.storage.completeTask({\n taskId: this.task.taskId,\n status: result === 'failed' ? 'failed' : 'completed',\n eventBody: {\n message: `Run completed with status: ${result}`,\n ...metadata,\n },\n });\n this.isDone = true;\n if (this.heartbeatTimeoutId) {\n clearTimeout(this.heartbeatTimeoutId);\n }\n }\n\n private startTimeout() {\n this.heartbeatTimeoutId = setTimeout(async () => {\n try {\n await this.storage.heartbeatTask(this.task.taskId);\n this.startTimeout();\n } catch (error) {\n this.isDone = true;\n\n this.logger.error(\n `Heartbeat for task ${this.task.taskId} failed`,\n error,\n );\n }\n }, 1000);\n }\n\n async getInitiatorCredentials(): Promise<BackstageCredentials> {\n const secrets = this.task.secrets as InternalTaskSecrets;\n\n if (secrets && secrets.__initiatorCredentials) {\n return JSON.parse(secrets.__initiatorCredentials);\n }\n if (!this.auth) {\n throw new Error(\n 'Failed to create none credentials in scaffolder task. The TaskManager has not been initialized with an auth service implementation',\n );\n }\n return this.auth.getNoneCredentials();\n }\n}\n\n/**\n * Stores the state of the current claimed task passed to the TaskContext\n *\n * @public\n */\nexport interface CurrentClaimedTask {\n /**\n * The TaskSpec of the current claimed task.\n */\n spec: TaskSpec;\n /**\n * The uuid of the current claimed task.\n */\n taskId: string;\n /**\n * The secrets that are stored with the task.\n */\n secrets?: TaskSecrets;\n /**\n * The state of checkpoints of the task.\n */\n state?: JsonObject;\n /**\n * The creator of the task.\n */\n createdBy?: string;\n /**\n * The workspace of the task.\n */\n workspace?: Promise<Buffer>;\n}\n\nexport class StorageTaskBroker implements TaskBroker {\n constructor(\n private readonly storage: TaskStore,\n private readonly logger: Logger,\n private readonly config?: Config,\n private readonly auth?: AuthService,\n private readonly additionalWorkspaceProviders?: Record<\n string,\n WorkspaceProvider\n >,\n ) {}\n\n async list(options?: {\n createdBy?: string;\n status?: TaskStatus;\n filters?: {\n createdBy?: string | string[];\n status?: TaskStatus | TaskStatus[];\n };\n pagination?: {\n limit?: number;\n offset?: number;\n };\n order?: { order: 'asc' | 'desc'; field: string }[];\n }): Promise<{ tasks: SerializedTask[]; totalTasks?: number }> {\n if (!this.storage.list) {\n throw new Error(\n 'TaskStore does not implement the list method. Please implement the list method to be able to list tasks',\n );\n }\n return await this.storage.list(options ?? {});\n }\n\n private deferredDispatch = createDeferred();\n\n private async registerCancellable(\n taskId: string,\n abortController: AbortController,\n ) {\n let shouldUnsubscribe = false;\n const subscription = this.event$({ taskId, after: undefined }).subscribe({\n error: _ => {\n subscription.unsubscribe();\n },\n next: ({ events }) => {\n for (const event of events) {\n if (event.type === 'cancelled') {\n abortController.abort();\n shouldUnsubscribe = true;\n }\n\n if (event.type === 'completion' && !event.isTaskRecoverable) {\n shouldUnsubscribe = true;\n }\n }\n if (shouldUnsubscribe) {\n subscription.unsubscribe();\n }\n },\n });\n }\n\n public async recoverTasks(): Promise<void> {\n const enabled =\n (this.config &&\n this.config.getOptionalBoolean(\n 'scaffolder.EXPERIMENTAL_recoverTasks',\n )) ??\n false;\n\n if (enabled) {\n const defaultTimeout = { seconds: 30 };\n const timeout = readDuration(\n this.config,\n 'scaffolder.EXPERIMENTAL_recoverTasksTimeout',\n defaultTimeout,\n );\n const { ids: recoveredTaskIds } = (await this.storage.recoverTasks?.({\n timeout,\n })) ?? { ids: [] };\n if (recoveredTaskIds.length > 0) {\n this.signalDispatch();\n }\n }\n }\n\n /**\n * {@inheritdoc TaskBroker.claim}\n */\n async claim(): Promise<TaskContext> {\n for (;;) {\n const pendingTask = await this.storage.claimTask();\n if (pendingTask) {\n const abortController = new AbortController();\n await this.registerCancellable(pendingTask.id, abortController);\n return TaskManager.create(\n {\n taskId: pendingTask.id,\n spec: pendingTask.spec,\n secrets: pendingTask.secrets,\n createdBy: pendingTask.createdBy,\n state: pendingTask.state,\n },\n this.storage,\n abortController.signal,\n this.logger,\n this.auth,\n this.config,\n this.additionalWorkspaceProviders,\n );\n }\n\n await this.waitForDispatch();\n }\n }\n\n /**\n * {@inheritdoc TaskBroker.dispatch}\n */\n async dispatch(\n options: TaskBrokerDispatchOptions,\n ): Promise<{ taskId: string }> {\n const taskRow = await this.storage.createTask(options);\n this.signalDispatch();\n return {\n taskId: taskRow.taskId,\n };\n }\n\n /**\n * {@inheritdoc TaskBroker.get}\n */\n async get(taskId: string): Promise<SerializedTask> {\n return this.storage.getTask(taskId);\n }\n\n /**\n * {@inheritdoc TaskBroker.event$}\n */\n event$(options: {\n taskId: string;\n after?: number;\n }): Observable<{ events: SerializedTaskEvent[] }> {\n return new ObservableImpl(observer => {\n const { taskId } = options;\n\n let after = options.after;\n let cancelled = false;\n\n (async () => {\n const task = await this.storage.getTask(taskId);\n const isTaskRecoverable =\n task.spec.EXPERIMENTAL_recovery?.EXPERIMENTAL_strategy ===\n 'startOver';\n\n while (!cancelled) {\n const result = await this.storage.listEvents({\n isTaskRecoverable,\n taskId,\n after,\n });\n const { events } = result;\n if (events.length) {\n after = events[events.length - 1].id;\n observer.next(result);\n }\n\n await new Promise(resolve => setTimeout(resolve, 1000));\n }\n })();\n\n return () => {\n cancelled = true;\n };\n });\n }\n\n /**\n * {@inheritdoc TaskBroker.vacuumTasks}\n */\n async vacuumTasks(options: { timeoutS: number }): Promise<void> {\n const { tasks } = await this.storage.listStaleTasks(options);\n await Promise.all(\n tasks.map(async task => {\n try {\n await this.storage.completeTask({\n taskId: task.taskId,\n status: 'failed',\n eventBody: {\n message:\n 'The task was cancelled because the task worker lost connection to the task broker',\n },\n });\n } catch (error) {\n this.logger.warn(`Failed to cancel task '${task.taskId}', ${error}`);\n }\n }),\n );\n }\n\n private waitForDispatch() {\n return this.deferredDispatch;\n }\n\n private signalDispatch() {\n this.deferredDispatch.resolve();\n this.deferredDispatch = createDeferred();\n }\n\n async cancel(taskId: string) {\n const { events } = await this.storage.listEvents({ taskId });\n const currentStepId =\n events.length > 0\n ? events\n .filter(({ body }) => body?.stepId)\n .reduce((prev, curr) => (prev.id > curr.id ? prev : curr)).body\n .stepId\n : 0;\n\n await this.storage.cancelTask?.({\n taskId,\n body: {\n message: `Step ${currentStepId} has been cancelled.`,\n stepId: currentStepId,\n status: 'cancelled',\n },\n });\n }\n\n async retry?(taskId: string): Promise<void> {\n await this.storage.retryTask?.({ taskId });\n this.signalDispatch();\n }\n}\n"],"names":["DefaultWorkspaceService","createDeferred","readDuration","ObservableImpl"],"mappings":"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"}
@@ -10,12 +10,12 @@ var alpha = require('@backstage/plugin-scaffolder-common/alpha');
10
10
  var express = require('express');
11
11
  var Router = require('express-promise-router');
12
12
  var jsonschema = require('jsonschema');
13
- var zod = require('zod');
13
+ var z = require('zod');
14
14
  require('@backstage/plugin-scaffolder-node');
15
15
  require('../scaffolder/actions/builtin/catalog/register.examples.cjs.js');
16
16
  require('fs-extra');
17
17
  require('yaml');
18
- require('@backstage/backend-plugin-api');
18
+ var backendPluginApi = require('@backstage/backend-plugin-api');
19
19
  require('../scaffolder/actions/builtin/catalog/write.examples.cjs.js');
20
20
  require('../scaffolder/actions/builtin/catalog/fetch.examples.cjs.js');
21
21
  var createBuiltinActions = require('../scaffolder/actions/builtin/createBuiltinActions.cjs.js');
@@ -34,6 +34,7 @@ require('../scaffolder/actions/builtin/fetch/template.examples.cjs.js');
34
34
  require('../scaffolder/actions/builtin/fetch/templateFile.examples.cjs.js');
35
35
  require('../scaffolder/actions/builtin/filesystem/delete.examples.cjs.js');
36
36
  require('../scaffolder/actions/builtin/filesystem/rename.examples.cjs.js');
37
+ require('../scaffolder/actions/builtin/filesystem/read.cjs.js');
37
38
  require('@backstage/plugin-scaffolder-backend-module-github');
38
39
  require('@backstage/plugin-scaffolder-backend-module-gitlab');
39
40
  require('@backstage/plugin-scaffolder-backend-module-azure');
@@ -50,6 +51,8 @@ var helpers = require('./helpers.cjs.js');
50
51
  var pluginPermissionNode = require('@backstage/plugin-permission-node');
51
52
  var rules = require('./rules.cjs.js');
52
53
  var checkPermissions = require('../util/checkPermissions.cjs.js');
54
+ var url = require('url');
55
+ var uuid = require('uuid');
53
56
 
54
57
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
55
58
 
@@ -524,12 +527,12 @@ data: ${JSON.stringify(event)}
524
527
  permissions: [alpha.taskCreatePermission],
525
528
  permissionService: permissions
526
529
  });
527
- const bodySchema = zod.z.object({
528
- template: zod.z.unknown(),
529
- values: zod.z.record(zod.z.unknown()),
530
- secrets: zod.z.record(zod.z.string()).optional(),
531
- directoryContents: zod.z.array(
532
- zod.z.object({ path: zod.z.string(), base64Content: zod.z.string() })
530
+ const bodySchema = z.z.object({
531
+ template: z.z.unknown(),
532
+ values: z.z.record(z.z.unknown()),
533
+ secrets: z.z.record(z.z.string()).optional(),
534
+ directoryContents: z.z.array(
535
+ z.z.object({ path: z.z.string(), base64Content: z.z.string() })
533
536
  )
534
537
  });
535
538
  const body = await bodySchema.parseAsync(req.body).catch((e) => {
@@ -557,6 +560,20 @@ data: ${JSON.stringify(event)}
557
560
  id: step.id ?? `step-${index + 1}`,
558
561
  name: step.name ?? step.action
559
562
  }));
563
+ const dryRunId = uuid.v4();
564
+ const contentsPath = backendPluginApi.resolveSafeChildPath(
565
+ workingDirectory,
566
+ `dry-run-content-${dryRunId}`
567
+ );
568
+ const templateInfo = {
569
+ entityRef: catalogModel.stringifyEntityRef(template),
570
+ entity: {
571
+ metadata: template.metadata
572
+ },
573
+ baseUrl: url.pathToFileURL(
574
+ backendPluginApi.resolveSafeChildPath(contentsPath, "template.yaml")
575
+ ).toString()
576
+ };
560
577
  const result = await dryRunner({
561
578
  spec: {
562
579
  apiVersion: template.apiVersion,
@@ -568,6 +585,7 @@ data: ${JSON.stringify(event)}
568
585
  ref: userEntityRef
569
586
  }
570
587
  },
588
+ templateInfo,
571
589
  directoryContents: (body.directoryContents ?? []).map((file) => ({
572
590
  path: file.path,
573
591
  content: Buffer.from(file.base64Content, "base64")