@backstage/plugin-scaffolder-backend 0.15.18 → 0.15.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,71 @@
1
1
  # @backstage/plugin-scaffolder-backend
2
2
 
3
+ ## 0.15.21
4
+
5
+ ### Patch Changes
6
+
7
+ - b05d303226: Added the ability to support supplying secrets when creating tasks in the `scaffolder-backend`.
8
+
9
+ **deprecation**: Deprecated `ctx.token` from actions in the `scaffolder-backend`. Please move to using `ctx.secrets.backstageToken` instead.
10
+
11
+ **deprecation**: Deprecated `task.token` in `TaskSpec` in the `scaffolder-backend`. Please move to using `task.secrets.backstageToken` instead.
12
+
13
+ - Updated dependencies
14
+ - @backstage/plugin-catalog-backend@0.21.0
15
+ - @backstage/integration@0.7.2
16
+ - @backstage/backend-common@0.10.4
17
+ - @backstage/config@0.1.13
18
+ - @backstage/catalog-model@0.9.10
19
+ - @backstage/catalog-client@0.5.5
20
+ - @backstage/plugin-scaffolder-backend-module-cookiecutter@0.1.9
21
+ - @backstage/plugin-scaffolder-common@0.1.3
22
+
23
+ ## 0.15.21-next.0
24
+
25
+ ### Patch Changes
26
+
27
+ - Updated dependencies
28
+ - @backstage/plugin-catalog-backend@0.21.0-next.0
29
+ - @backstage/backend-common@0.10.4-next.0
30
+ - @backstage/config@0.1.13-next.0
31
+ - @backstage/catalog-model@0.9.10-next.0
32
+ - @backstage/catalog-client@0.5.5-next.0
33
+ - @backstage/integration@0.7.2-next.0
34
+ - @backstage/plugin-scaffolder-backend-module-cookiecutter@0.1.9-next.0
35
+ - @backstage/plugin-scaffolder-common@0.1.3-next.0
36
+
37
+ ## 0.15.20
38
+
39
+ ### Patch Changes
40
+
41
+ - 9fbd3b90ae: fix: Register plugin to prioritise Component kind for entityRef
42
+ - 451ef0aa07: Fix token pass-through for software templates using beta 3 version
43
+ - 5333451def: Cleaned up API exports
44
+ - 3b4d8caff6: Allow a GitHubCredentialsProvider to be passed to the GitHub scaffolder tasks actions.
45
+ - Updated dependencies
46
+ - @backstage/config@0.1.12
47
+ - @backstage/integration@0.7.1
48
+ - @backstage/backend-common@0.10.3
49
+ - @backstage/plugin-catalog-backend@0.20.0
50
+ - @backstage/errors@0.2.0
51
+ - @backstage/catalog-client@0.5.4
52
+ - @backstage/catalog-model@0.9.9
53
+ - @backstage/plugin-scaffolder-backend-module-cookiecutter@0.1.8
54
+
55
+ ## 0.15.19
56
+
57
+ ### Patch Changes
58
+
59
+ - 7d4b4e937c: Uptake changes to the GitHub Credentials Provider interface.
60
+ - d078377f67: Support navigating back to pre-filled templates to update inputs of scaffolder tasks for resubmission
61
+ - 5f8ceba1b1: Support custom file name for `catalog:write` action
62
+ - Updated dependencies
63
+ - @backstage/backend-common@0.10.1
64
+ - @backstage/plugin-catalog-backend@0.19.4
65
+ - @backstage/plugin-scaffolder-common@0.1.2
66
+ - @backstage/integration@0.7.0
67
+ - @backstage/plugin-scaffolder-backend-module-cookiecutter@0.1.7
68
+
3
69
  ## 0.15.18
4
70
 
5
71
  ### Patch Changes
package/dist/index.cjs.js CHANGED
@@ -7,6 +7,7 @@ var catalogModel = require('@backstage/catalog-model');
7
7
  var fs = require('fs-extra');
8
8
  var yaml = require('yaml');
9
9
  var backendCommon = require('@backstage/backend-common');
10
+ var integration = require('@backstage/integration');
10
11
  var path = require('path');
11
12
  var globby = require('globby');
12
13
  var isbinaryfile = require('isbinaryfile');
@@ -16,7 +17,6 @@ var child_process = require('child_process');
16
17
  var stream = require('stream');
17
18
  var azureDevopsNodeApi = require('azure-devops-node-api');
18
19
  var fetch = require('node-fetch');
19
- var integration = require('@backstage/integration');
20
20
  var rest = require('@octokit/rest');
21
21
  var lodash = require('lodash');
22
22
  var octokitPluginCreatePullRequest = require('octokit-plugin-create-pull-request');
@@ -119,7 +119,7 @@ function createCatalogRegisterAction(options) {
119
119
  }
120
120
  },
121
121
  async handler(ctx) {
122
- var _a;
122
+ var _a, _b;
123
123
  const { input } = ctx;
124
124
  let catalogInfoUrl;
125
125
  if ("catalogInfoUrl" in input) {
@@ -139,16 +139,23 @@ function createCatalogRegisterAction(options) {
139
139
  await catalogClient.addLocation({
140
140
  type: "url",
141
141
  target: catalogInfoUrl
142
- }, ctx.token ? { token: ctx.token } : {});
142
+ }, ((_a = ctx.secrets) == null ? void 0 : _a.backstageToken) ? { token: ctx.secrets.backstageToken } : {});
143
143
  try {
144
144
  const result = await catalogClient.addLocation({
145
145
  dryRun: true,
146
146
  type: "url",
147
147
  target: catalogInfoUrl
148
- }, ctx.token ? { token: ctx.token } : {});
148
+ }, ((_b = ctx.secrets) == null ? void 0 : _b.backstageToken) ? { token: ctx.secrets.backstageToken } : {});
149
149
  if (result.entities.length > 0) {
150
150
  const { entities } = result;
151
- const entity = (_a = entities.find((e) => !e.metadata.name.startsWith("generated-"))) != null ? _a : entities[0];
151
+ let entity;
152
+ entity = entities.find((e) => !e.metadata.name.startsWith("generated-") && e.kind === "Component");
153
+ if (!entity) {
154
+ entity = entities.find((e) => !e.metadata.name.startsWith("generated-"));
155
+ }
156
+ if (!entity) {
157
+ entity = entities[0];
158
+ }
152
159
  ctx.output("entityRef", catalogModel.stringifyEntityRef(entity));
153
160
  }
154
161
  } catch (e) {
@@ -169,6 +176,11 @@ function createCatalogWriteAction() {
169
176
  input: {
170
177
  type: "object",
171
178
  properties: {
179
+ filePath: {
180
+ title: "Catalog file path",
181
+ description: "Defaults to catalog-info.yaml",
182
+ type: "string"
183
+ },
172
184
  entity: {
173
185
  title: "Entity info to write catalog-info.yaml",
174
186
  description: "You can provide the same values used in the Entity schema.",
@@ -179,8 +191,9 @@ function createCatalogWriteAction() {
179
191
  },
180
192
  async handler(ctx) {
181
193
  ctx.logStream.write(`Writing catalog-info.yaml`);
182
- const { entity } = ctx.input;
183
- await fs__default["default"].writeFile(backendCommon.resolveSafeChildPath(ctx.workspacePath, "catalog-info.yaml"), yaml__namespace.stringify(entity));
194
+ const { filePath, entity } = ctx.input;
195
+ const path = filePath != null ? filePath : "catalog-info.yaml";
196
+ await fs__default["default"].writeFile(backendCommon.resolveSafeChildPath(ctx.workspacePath, path), yaml__namespace.stringify(entity));
184
197
  }
185
198
  });
186
199
  }
@@ -1144,12 +1157,9 @@ function createPublishFileAction() {
1144
1157
  }
1145
1158
 
1146
1159
  class OctokitProvider {
1147
- constructor(integrations) {
1160
+ constructor(integrations, githubCredentialsProvider) {
1148
1161
  this.integrations = integrations;
1149
- this.credentialsProviders = new Map(integrations.github.list().map((integration$1) => {
1150
- const provider = integration.GithubCredentialsProvider.create(integration$1.config);
1151
- return [integration$1.config.host, provider];
1152
- }));
1162
+ this.githubCredentialsProvider = githubCredentialsProvider || integration.DefaultGithubCredentialsProvider.fromIntegrations(this.integrations);
1153
1163
  }
1154
1164
  async getOctokit(repoUrl) {
1155
1165
  var _a;
@@ -1161,11 +1171,7 @@ class OctokitProvider {
1161
1171
  if (!integrationConfig) {
1162
1172
  throw new errors.InputError(`No integration for host ${host}`);
1163
1173
  }
1164
- const credentialsProvider = this.credentialsProviders.get(host);
1165
- if (!credentialsProvider) {
1166
- throw new errors.InputError(`No matching credentials for host ${host}, please check your integrations config`);
1167
- }
1168
- const { token } = await credentialsProvider.getCredentials({
1174
+ const { token } = await this.githubCredentialsProvider.getCredentials({
1169
1175
  url: `https://${host}/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}`
1170
1176
  });
1171
1177
  if (!token) {
@@ -1181,8 +1187,8 @@ class OctokitProvider {
1181
1187
  }
1182
1188
 
1183
1189
  function createPublishGithubAction(options) {
1184
- const { integrations, config } = options;
1185
- const octokitProvider = new OctokitProvider(integrations);
1190
+ const { integrations, config, githubCredentialsProvider } = options;
1191
+ const octokitProvider = new OctokitProvider(integrations, githubCredentialsProvider || integration.DefaultGithubCredentialsProvider.fromIntegrations(integrations));
1186
1192
  return createTemplateAction({
1187
1193
  id: "publish:github",
1188
1194
  description: "Initializes a git repository of contents in workspace and publishes it to GitHub.",
@@ -1382,6 +1388,7 @@ class GithubResponseError extends errors.CustomErrorBase {
1382
1388
  }
1383
1389
  const defaultClientFactory = async ({
1384
1390
  integrations,
1391
+ githubCredentialsProvider,
1385
1392
  owner,
1386
1393
  repo,
1387
1394
  host = "github.com"
@@ -1391,10 +1398,7 @@ const defaultClientFactory = async ({
1391
1398
  if (!integrationConfig) {
1392
1399
  throw new errors.InputError(`No integration for host ${host}`);
1393
1400
  }
1394
- const credentialsProvider = integration.GithubCredentialsProvider.create(integrationConfig);
1395
- if (!credentialsProvider) {
1396
- throw new errors.InputError(`No matching credentials for host ${host}, please check your integrations config`);
1397
- }
1401
+ const credentialsProvider = githubCredentialsProvider || integration.SingleInstanceGithubCredentialsProvider.create(integrationConfig);
1398
1402
  const { token } = await credentialsProvider.getCredentials({
1399
1403
  url: `https://${host}/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}`
1400
1404
  });
@@ -1409,6 +1413,7 @@ const defaultClientFactory = async ({
1409
1413
  };
1410
1414
  const createPublishGithubPullRequestAction = ({
1411
1415
  integrations,
1416
+ githubCredentialsProvider,
1412
1417
  clientFactory = defaultClientFactory
1413
1418
  }) => {
1414
1419
  return createTemplateAction({
@@ -1475,7 +1480,13 @@ const createPublishGithubPullRequestAction = ({
1475
1480
  if (!owner) {
1476
1481
  throw new errors.InputError(`No owner provided for host: ${host}, and repo ${repo}`);
1477
1482
  }
1478
- const client = await clientFactory({ integrations, host, owner, repo });
1483
+ const client = await clientFactory({
1484
+ integrations,
1485
+ githubCredentialsProvider,
1486
+ host,
1487
+ owner,
1488
+ repo
1489
+ });
1479
1490
  const fileRoot = sourcePath ? backendCommon.resolveSafeChildPath(ctx.workspacePath, sourcePath) : ctx.workspacePath;
1480
1491
  const localFilePaths = await globby__default["default"](["./**", "./**/.*", "!.git"], {
1481
1492
  cwd: fileRoot,
@@ -1737,8 +1748,8 @@ const createPublishGitlabMergeRequestAction = (options) => {
1737
1748
  };
1738
1749
 
1739
1750
  function createGithubActionsDispatchAction(options) {
1740
- const { integrations } = options;
1741
- const octokitProvider = new OctokitProvider(integrations);
1751
+ const { integrations, githubCredentialsProvider } = options;
1752
+ const octokitProvider = new OctokitProvider(integrations, githubCredentialsProvider || integration.DefaultGithubCredentialsProvider.fromIntegrations(integrations));
1742
1753
  return createTemplateAction({
1743
1754
  id: "github:actions:dispatch",
1744
1755
  description: "Dispatches a GitHub Action workflow for a given branch or tag",
@@ -1781,8 +1792,8 @@ function createGithubActionsDispatchAction(options) {
1781
1792
  }
1782
1793
 
1783
1794
  function createGithubWebhookAction(options) {
1784
- const { integrations, defaultWebhookSecret } = options;
1785
- const octokitProvider = new OctokitProvider(integrations);
1795
+ const { integrations, defaultWebhookSecret, githubCredentialsProvider } = options;
1796
+ const octokitProvider = new OctokitProvider(integrations, githubCredentialsProvider != null ? githubCredentialsProvider : integration.DefaultGithubCredentialsProvider.fromIntegrations(integrations));
1786
1797
  const eventNames = webhooks.emitterEventNames.filter((event) => !event.includes("."));
1787
1798
  return createTemplateAction({
1788
1799
  id: "github:webhook",
@@ -1882,6 +1893,7 @@ function createGithubWebhookAction(options) {
1882
1893
 
1883
1894
  const createBuiltinActions = (options) => {
1884
1895
  const { reader, integrations, containerRunner, catalogClient, config } = options;
1896
+ const githubCredentialsProvider = integration.DefaultGithubCredentialsProvider.fromIntegrations(integrations);
1885
1897
  const actions = [
1886
1898
  createFetchPlainAction({
1887
1899
  reader,
@@ -1893,10 +1905,12 @@ const createBuiltinActions = (options) => {
1893
1905
  }),
1894
1906
  createPublishGithubAction({
1895
1907
  integrations,
1896
- config
1908
+ config,
1909
+ githubCredentialsProvider
1897
1910
  }),
1898
1911
  createPublishGithubPullRequestAction({
1899
- integrations
1912
+ integrations,
1913
+ githubCredentialsProvider
1900
1914
  }),
1901
1915
  createPublishGitlabAction({
1902
1916
  integrations,
@@ -1919,10 +1933,12 @@ const createBuiltinActions = (options) => {
1919
1933
  createFilesystemDeleteAction(),
1920
1934
  createFilesystemRenameAction(),
1921
1935
  createGithubActionsDispatchAction({
1922
- integrations
1936
+ integrations,
1937
+ githubCredentialsProvider
1923
1938
  }),
1924
1939
  createGithubWebhookAction({
1925
- integrations
1940
+ integrations,
1941
+ githubCredentialsProvider
1926
1942
  })
1927
1943
  ];
1928
1944
  if (containerRunner) {
@@ -2008,7 +2024,8 @@ class DatabaseTaskStore {
2008
2024
  }
2009
2025
  const updateCount = await tx("tasks").where({ id: task.id, status: "open" }).update({
2010
2026
  status: "processing",
2011
- last_heartbeat_at: this.db.fn.now()
2027
+ last_heartbeat_at: this.db.fn.now(),
2028
+ secrets: null
2012
2029
  });
2013
2030
  if (updateCount < 1) {
2014
2031
  return void 0;
@@ -2072,8 +2089,7 @@ class DatabaseTaskStore {
2072
2089
  id: taskId,
2073
2090
  status: oldStatus
2074
2091
  }).update({
2075
- status,
2076
- secrets: null
2092
+ status
2077
2093
  });
2078
2094
  if (updateCount !== 1) {
2079
2095
  throw new errors.ConflictError(`Failed to update status to '${status}' for taskId ${taskId}`);
@@ -2286,7 +2302,7 @@ class HandlebarsWorkflowRunner {
2286
2302
  this.handlebars.registerHelper("eq", (a, b) => a === b);
2287
2303
  }
2288
2304
  async execute(task) {
2289
- var _a, _b;
2305
+ var _a, _b, _c;
2290
2306
  if (!isValidTaskSpec$1(task.spec)) {
2291
2307
  throw new errors.InputError(`Task spec is not a valid v1beta2 task spec`);
2292
2308
  }
@@ -2390,6 +2406,7 @@ class HandlebarsWorkflowRunner {
2390
2406
  logStream: stream$1,
2391
2407
  input,
2392
2408
  token: (_b = task.secrets) == null ? void 0 : _b.token,
2409
+ secrets: (_c = task.secrets) != null ? _c : {},
2393
2410
  workspacePath,
2394
2411
  async createTemporaryDirectory() {
2395
2412
  const tmpDir = await fs__default["default"].mkdtemp(`${workspacePath}_step-${step.id}-`);
@@ -2515,7 +2532,7 @@ class NunjucksWorkflowRunner {
2515
2532
  });
2516
2533
  }
2517
2534
  async execute(task) {
2518
- var _a, _b;
2535
+ var _a, _b, _c, _d;
2519
2536
  if (!isValidTaskSpec(task.spec)) {
2520
2537
  throw new errors.InputError("Wrong template version executed with the workflow engine");
2521
2538
  }
@@ -2564,6 +2581,8 @@ class NunjucksWorkflowRunner {
2564
2581
  await action.handler({
2565
2582
  baseUrl: task.spec.baseUrl,
2566
2583
  input,
2584
+ token: (_c = task.secrets) == null ? void 0 : _c.token,
2585
+ secrets: (_d = task.secrets) != null ? _d : {},
2567
2586
  logger: taskLogger,
2568
2587
  logStream: streamLogger,
2569
2588
  workspacePath,
@@ -2845,6 +2864,8 @@ async function createRouter(options) {
2845
2864
  throw new errors.InputError(`Unsupported apiVersion field in schema entity, ${template.apiVersion}`);
2846
2865
  }
2847
2866
  const result = await taskBroker.dispatch(taskSpec, {
2867
+ ...req.body.secrets,
2868
+ backstageToken: token,
2848
2869
  token
2849
2870
  });
2850
2871
  res.status(201).json({ id: result.taskId });