@backstage/plugin-scaffolder-backend 1.4.0 → 1.5.0-next.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs.js CHANGED
@@ -147,7 +147,9 @@ function createCatalogRegisterAction(options) {
147
147
  const { repoContentsUrl, catalogInfoPath = "/catalog-info.yaml" } = input;
148
148
  const integration = integrations.byUrl(repoContentsUrl);
149
149
  if (!integration) {
150
- throw new errors.InputError(`No integration found for host ${repoContentsUrl}`);
150
+ throw new errors.InputError(
151
+ `No integration found for host ${repoContentsUrl}`
152
+ );
151
153
  }
152
154
  catalogInfoUrl = integration.resolveUrl({
153
155
  base: repoContentsUrl,
@@ -155,22 +157,32 @@ function createCatalogRegisterAction(options) {
155
157
  });
156
158
  }
157
159
  ctx.logger.info(`Registering ${catalogInfoUrl} in the catalog`);
158
- await catalogClient.addLocation({
159
- type: "url",
160
- target: catalogInfoUrl
161
- }, ((_a = ctx.secrets) == null ? void 0 : _a.backstageToken) ? { token: ctx.secrets.backstageToken } : {});
162
- try {
163
- const result = await catalogClient.addLocation({
164
- dryRun: true,
160
+ await catalogClient.addLocation(
161
+ {
165
162
  type: "url",
166
163
  target: catalogInfoUrl
167
- }, ((_b = ctx.secrets) == null ? void 0 : _b.backstageToken) ? { token: ctx.secrets.backstageToken } : {});
164
+ },
165
+ ((_a = ctx.secrets) == null ? void 0 : _a.backstageToken) ? { token: ctx.secrets.backstageToken } : {}
166
+ );
167
+ try {
168
+ const result = await catalogClient.addLocation(
169
+ {
170
+ dryRun: true,
171
+ type: "url",
172
+ target: catalogInfoUrl
173
+ },
174
+ ((_b = ctx.secrets) == null ? void 0 : _b.backstageToken) ? { token: ctx.secrets.backstageToken } : {}
175
+ );
168
176
  if (result.entities.length > 0) {
169
177
  const { entities } = result;
170
178
  let entity;
171
- entity = entities.find((e) => !e.metadata.name.startsWith("generated-") && e.kind === "Component");
179
+ entity = entities.find(
180
+ (e) => !e.metadata.name.startsWith("generated-") && e.kind === "Component"
181
+ );
172
182
  if (!entity) {
173
- entity = entities.find((e) => !e.metadata.name.startsWith("generated-"));
183
+ entity = entities.find(
184
+ (e) => !e.metadata.name.startsWith("generated-")
185
+ );
174
186
  }
175
187
  if (!entity) {
176
188
  entity = entities[0];
@@ -213,7 +225,10 @@ function createCatalogWriteAction() {
213
225
  ctx.logStream.write(`Writing catalog-info.yaml`);
214
226
  const { filePath, entity } = ctx.input;
215
227
  const path = filePath != null ? filePath : "catalog-info.yaml";
216
- await fs__default["default"].writeFile(backendCommon.resolveSafeChildPath(ctx.workspacePath, path), yaml__namespace.stringify(entity));
228
+ await fs__default["default"].writeFile(
229
+ backendCommon.resolveSafeChildPath(ctx.workspacePath, path),
230
+ yaml__namespace.stringify(entity)
231
+ );
217
232
  }
218
233
  });
219
234
  }
@@ -249,18 +264,22 @@ function createDebugLogAction() {
249
264
  }
250
265
  if ((_b = ctx.input) == null ? void 0 : _b.listWorkspace) {
251
266
  const files = await recursiveReadDir(ctx.workspacePath);
252
- ctx.logStream.write(`Workspace:
253
- ${files.map((f) => ` - ${path.relative(ctx.workspacePath, f)}`).join("\n")}`);
267
+ ctx.logStream.write(
268
+ `Workspace:
269
+ ${files.map((f) => ` - ${path.relative(ctx.workspacePath, f)}`).join("\n")}`
270
+ );
254
271
  }
255
272
  }
256
273
  });
257
274
  }
258
275
  async function recursiveReadDir(dir) {
259
276
  const subdirs = await fs.readdir(dir);
260
- const files = await Promise.all(subdirs.map(async (subdir) => {
261
- const res = path.join(dir, subdir);
262
- return (await fs.stat(res)).isDirectory() ? recursiveReadDir(res) : [res];
263
- }));
277
+ const files = await Promise.all(
278
+ subdirs.map(async (subdir) => {
279
+ const res = path.join(dir, subdir);
280
+ return (await fs.stat(res)).isDirectory() ? recursiveReadDir(res) : [res];
281
+ })
282
+ );
264
283
  return files.reduce((a, f) => a.concat(f), []);
265
284
  }
266
285
 
@@ -295,7 +314,9 @@ async function fetchContents({
295
314
  base: baseUrl
296
315
  });
297
316
  } else {
298
- throw new errors.InputError(`Failed to fetch, template location could not be determined and the fetch URL is relative, ${fetchUrl}`);
317
+ throw new errors.InputError(
318
+ `Failed to fetch, template location could not be determined and the fetch URL is relative, ${fetchUrl}`
319
+ );
299
320
  }
300
321
  const res = await reader.readTree(readUrl);
301
322
  await fs__default["default"].ensureDir(outputPath);
@@ -424,13 +445,21 @@ class SecureTemplater {
424
445
  sandbox.parseRepoUrl = (url) => JSON.stringify(parseRepoUrl(url));
425
446
  }
426
447
  if (additionalTemplateFilters) {
427
- sandbox.additionalTemplateFilters = Object.fromEntries(Object.entries(additionalTemplateFilters).filter(([_, filterFunction]) => !!filterFunction).map(([filterName, filterFunction]) => [
428
- filterName,
429
- (...args) => JSON.stringify(filterFunction(...args))
430
- ]));
448
+ sandbox.additionalTemplateFilters = Object.fromEntries(
449
+ Object.entries(additionalTemplateFilters).filter(([_, filterFunction]) => !!filterFunction).map(([filterName, filterFunction]) => [
450
+ filterName,
451
+ (...args) => JSON.stringify(filterFunction(...args))
452
+ ])
453
+ );
431
454
  }
432
455
  const vm = new vm2.VM({ sandbox });
433
- const nunjucksSource = await fs__default["default"].readFile(backendCommon.resolvePackagePath("@backstage/plugin-scaffolder-backend", "assets/nunjucks.js.txt"), "utf-8");
456
+ const nunjucksSource = await fs__default["default"].readFile(
457
+ backendCommon.resolvePackagePath(
458
+ "@backstage/plugin-scaffolder-backend",
459
+ "assets/nunjucks.js.txt"
460
+ ),
461
+ "utf-8"
462
+ );
434
463
  vm.run(mkScript(nunjucksSource));
435
464
  const render = (template, values) => {
436
465
  if (!vm) {
@@ -510,12 +539,16 @@ function createFetchTemplateAction(options) {
510
539
  const targetPath = (_a = ctx.input.targetPath) != null ? _a : "./";
511
540
  const outputDir = backendCommon.resolveSafeChildPath(ctx.workspacePath, targetPath);
512
541
  if (ctx.input.copyWithoutRender && ctx.input.copyWithoutTemplating) {
513
- throw new errors.InputError("Fetch action input copyWithoutRender and copyWithoutTemplating can not be used at the same time");
542
+ throw new errors.InputError(
543
+ "Fetch action input copyWithoutRender and copyWithoutTemplating can not be used at the same time"
544
+ );
514
545
  }
515
546
  let copyOnlyPatterns;
516
547
  let renderFilename;
517
548
  if (ctx.input.copyWithoutRender) {
518
- ctx.logger.warn("[Deprecated] Please use copyWithoutTemplating instead.");
549
+ ctx.logger.warn(
550
+ "[Deprecated] Please use copyWithoutTemplating instead."
551
+ );
519
552
  copyOnlyPatterns = ctx.input.copyWithoutRender;
520
553
  renderFilename = false;
521
554
  } else {
@@ -523,10 +556,14 @@ function createFetchTemplateAction(options) {
523
556
  renderFilename = true;
524
557
  }
525
558
  if (copyOnlyPatterns && !Array.isArray(copyOnlyPatterns)) {
526
- throw new errors.InputError("Fetch action input copyWithoutRender/copyWithoutTemplating must be an Array");
559
+ throw new errors.InputError(
560
+ "Fetch action input copyWithoutRender/copyWithoutTemplating must be an Array"
561
+ );
527
562
  }
528
563
  if (ctx.input.templateFileExtension && (copyOnlyPatterns || ctx.input.cookiecutterCompat)) {
529
- throw new errors.InputError("Fetch action input extension incompatible with copyWithoutRender/copyWithoutTemplating and cookiecutterCompat");
564
+ throw new errors.InputError(
565
+ "Fetch action input extension incompatible with copyWithoutRender/copyWithoutTemplating and cookiecutterCompat"
566
+ );
530
567
  }
531
568
  let extension = false;
532
569
  if (ctx.input.templateFileExtension) {
@@ -550,18 +587,27 @@ function createFetchTemplateAction(options) {
550
587
  markDirectories: true,
551
588
  followSymbolicLinks: false
552
589
  });
553
- const nonTemplatedEntries = new Set((await Promise.all((copyOnlyPatterns || []).map((pattern) => globby__default["default"](pattern, {
554
- cwd: templateDir,
555
- dot: true,
556
- onlyFiles: false,
557
- markDirectories: true,
558
- followSymbolicLinks: false
559
- })))).flat());
590
+ const nonTemplatedEntries = new Set(
591
+ (await Promise.all(
592
+ (copyOnlyPatterns || []).map(
593
+ (pattern) => globby__default["default"](pattern, {
594
+ cwd: templateDir,
595
+ dot: true,
596
+ onlyFiles: false,
597
+ markDirectories: true,
598
+ followSymbolicLinks: false
599
+ })
600
+ )
601
+ )).flat()
602
+ );
560
603
  const { cookiecutterCompat, values } = ctx.input;
561
604
  const context = {
562
605
  [cookiecutterCompat ? "cookiecutter" : "values"]: values
563
606
  };
564
- ctx.logger.info(`Processing ${allEntriesInTemplate.length} template files/directories with input values`, ctx.input.values);
607
+ ctx.logger.info(
608
+ `Processing ${allEntriesInTemplate.length} template files/directories with input values`,
609
+ ctx.input.values
610
+ );
565
611
  const renderTemplate = await SecureTemplater.loadRenderer({
566
612
  cookiecutterCompat: ctx.input.cookiecutterCompat,
567
613
  additionalTemplateFilters
@@ -591,22 +637,34 @@ function createFetchTemplateAction(options) {
591
637
  continue;
592
638
  }
593
639
  if (!renderContents && !extension) {
594
- ctx.logger.info(`Copying file/directory ${location} without processing.`);
640
+ ctx.logger.info(
641
+ `Copying file/directory ${location} without processing.`
642
+ );
595
643
  }
596
644
  if (location.endsWith("/")) {
597
- ctx.logger.info(`Writing directory ${location} to template output path.`);
645
+ ctx.logger.info(
646
+ `Writing directory ${location} to template output path.`
647
+ );
598
648
  await fs__default["default"].ensureDir(outputPath);
599
649
  } else {
600
650
  const inputFilePath = backendCommon.resolveSafeChildPath(templateDir, location);
601
651
  const stats = await fs__default["default"].promises.lstat(inputFilePath);
602
652
  if (stats.isSymbolicLink() || await isbinaryfile.isBinaryFile(inputFilePath)) {
603
- ctx.logger.info(`Copying file binary or symbolic link at ${location}, to template output path.`);
653
+ ctx.logger.info(
654
+ `Copying file binary or symbolic link at ${location}, to template output path.`
655
+ );
604
656
  await fs__default["default"].copy(inputFilePath, outputPath);
605
657
  } else {
606
658
  const statsObj = await fs__default["default"].stat(inputFilePath);
607
- ctx.logger.info(`Writing file ${location} to template output path with mode ${statsObj.mode}.`);
659
+ ctx.logger.info(
660
+ `Writing file ${location} to template output path with mode ${statsObj.mode}.`
661
+ );
608
662
  const inputFileContents = await fs__default["default"].readFile(inputFilePath, "utf-8");
609
- await fs__default["default"].outputFile(outputPath, renderContents ? renderTemplate(inputFileContents, context) : inputFileContents, { mode: statsObj.mode });
663
+ await fs__default["default"].outputFile(
664
+ outputPath,
665
+ renderContents ? renderTemplate(inputFileContents, context) : inputFileContents,
666
+ { mode: statsObj.mode }
667
+ );
610
668
  }
611
669
  }
612
670
  }
@@ -703,15 +761,23 @@ const createFilesystemRenameAction = () => {
703
761
  if (!file.from || !file.to) {
704
762
  throw new errors.InputError("each file must have a from and to property");
705
763
  }
706
- const sourceFilepath = backendCommon.resolveSafeChildPath(ctx.workspacePath, file.from);
764
+ const sourceFilepath = backendCommon.resolveSafeChildPath(
765
+ ctx.workspacePath,
766
+ file.from
767
+ );
707
768
  const destFilepath = backendCommon.resolveSafeChildPath(ctx.workspacePath, file.to);
708
769
  try {
709
770
  await fs__default["default"].move(sourceFilepath, destFilepath, {
710
771
  overwrite: (_b = file.overwrite) != null ? _b : false
711
772
  });
712
- ctx.logger.info(`File ${sourceFilepath} renamed to ${destFilepath} successfully`);
773
+ ctx.logger.info(
774
+ `File ${sourceFilepath} renamed to ${destFilepath} successfully`
775
+ );
713
776
  } catch (err) {
714
- ctx.logger.error(`Failed to rename file ${sourceFilepath} to ${destFilepath}:`, err);
777
+ ctx.logger.error(
778
+ `Failed to rename file ${sourceFilepath} to ${destFilepath}:`,
779
+ err
780
+ );
715
781
  throw err;
716
782
  }
717
783
  }
@@ -721,7 +787,10 @@ const createFilesystemRenameAction = () => {
721
787
 
722
788
  const getRepoSourceDirectory = (workspacePath, sourcePath) => {
723
789
  if (sourcePath) {
724
- const safeSuffix = path.normalize(sourcePath).replace(/^(\.\.(\/|\\|$))+/, "");
790
+ const safeSuffix = path.normalize(sourcePath).replace(
791
+ /^(\.\.(\/|\\|$))+/,
792
+ ""
793
+ );
725
794
  const path$1 = path.join(workspacePath, safeSuffix);
726
795
  if (!backendCommon.isChildPath(workspacePath, path$1)) {
727
796
  throw new Error("Invalid source path");
@@ -736,7 +805,9 @@ const parseRepoUrl = (repoUrl, integrations) => {
736
805
  try {
737
806
  parsed = new URL(`https://${repoUrl}`);
738
807
  } catch (error) {
739
- throw new errors.InputError(`Invalid repo URL passed to publisher, got ${repoUrl}, ${error}`);
808
+ throw new errors.InputError(
809
+ `Invalid repo URL passed to publisher, got ${repoUrl}, ${error}`
810
+ );
740
811
  }
741
812
  const host = parsed.host;
742
813
  const owner = (_a = parsed.searchParams.get("owner")) != null ? _a : void 0;
@@ -745,25 +816,35 @@ const parseRepoUrl = (repoUrl, integrations) => {
745
816
  const project = (_d = parsed.searchParams.get("project")) != null ? _d : void 0;
746
817
  const type = (_e = integrations.byHost(host)) == null ? void 0 : _e.type;
747
818
  if (!type) {
748
- throw new errors.InputError(`No matching integration configuration for host ${host}, please check your integrations config`);
819
+ throw new errors.InputError(
820
+ `No matching integration configuration for host ${host}, please check your integrations config`
821
+ );
749
822
  }
750
823
  if (type === "bitbucket") {
751
824
  if (host === "bitbucket.org") {
752
825
  if (!workspace) {
753
- throw new errors.InputError(`Invalid repo URL passed to publisher: ${repoUrl}, missing workspace`);
826
+ throw new errors.InputError(
827
+ `Invalid repo URL passed to publisher: ${repoUrl}, missing workspace`
828
+ );
754
829
  }
755
830
  }
756
831
  if (!project) {
757
- throw new errors.InputError(`Invalid repo URL passed to publisher: ${repoUrl}, missing project`);
832
+ throw new errors.InputError(
833
+ `Invalid repo URL passed to publisher: ${repoUrl}, missing project`
834
+ );
758
835
  }
759
836
  } else {
760
837
  if (!owner && type !== "gerrit") {
761
- throw new errors.InputError(`Invalid repo URL passed to publisher: ${repoUrl}, missing owner`);
838
+ throw new errors.InputError(
839
+ `Invalid repo URL passed to publisher: ${repoUrl}, missing owner`
840
+ );
762
841
  }
763
842
  }
764
843
  const repo = parsed.searchParams.get("repo");
765
844
  if (!repo) {
766
- throw new errors.InputError(`Invalid repo URL passed to publisher: ${repoUrl}, missing repo`);
845
+ throw new errors.InputError(
846
+ `Invalid repo URL passed to publisher: ${repoUrl}, missing repo`
847
+ );
767
848
  }
768
849
  return { host, owner, repo, organization, workspace, project };
769
850
  };
@@ -788,7 +869,9 @@ const executeShellCommand = async (options) => {
788
869
  });
789
870
  process.on("close", (code) => {
790
871
  if (code !== 0) {
791
- return reject(new Error(`Command ${command} failed, exit code: ${code}`));
872
+ return reject(
873
+ new Error(`Command ${command} failed, exit code: ${code}`)
874
+ );
792
875
  }
793
876
  return resolve();
794
877
  });
@@ -805,8 +888,7 @@ async function initRepoAndPush({
805
888
  }) {
806
889
  var _a, _b;
807
890
  const git = backendCommon.Git.fromAuth({
808
- username: auth.username,
809
- password: auth.password,
891
+ ...auth,
810
892
  logger
811
893
  });
812
894
  await git.init({
@@ -834,6 +916,39 @@ async function initRepoAndPush({
834
916
  remote: "origin"
835
917
  });
836
918
  }
919
+ async function commitAndPushRepo({
920
+ dir,
921
+ auth,
922
+ logger,
923
+ commitMessage,
924
+ gitAuthorInfo,
925
+ branch = "master",
926
+ remoteRef
927
+ }) {
928
+ var _a, _b;
929
+ const git = backendCommon.Git.fromAuth({
930
+ ...auth,
931
+ logger
932
+ });
933
+ await git.fetch({ dir });
934
+ await git.checkout({ dir, ref: branch });
935
+ await git.add({ dir, filepath: "." });
936
+ const authorInfo = {
937
+ name: (_a = gitAuthorInfo == null ? void 0 : gitAuthorInfo.name) != null ? _a : "Scaffolder",
938
+ email: (_b = gitAuthorInfo == null ? void 0 : gitAuthorInfo.email) != null ? _b : "scaffolder@backstage.io"
939
+ };
940
+ await git.commit({
941
+ dir,
942
+ message: commitMessage,
943
+ author: authorInfo,
944
+ committer: authorInfo
945
+ });
946
+ await git.push({
947
+ dir,
948
+ remote: "origin",
949
+ remoteRef: remoteRef != null ? remoteRef : `refs/heads/${branch}`
950
+ });
951
+ }
837
952
  const enableBranchProtectionOnDefaultRepoBranch = async ({
838
953
  repoName,
839
954
  client,
@@ -866,8 +981,12 @@ const enableBranchProtectionOnDefaultRepoBranch = async ({
866
981
  });
867
982
  } catch (e) {
868
983
  errors.assertError(e);
869
- if (e.message.includes("Upgrade to GitHub Pro or make this repository public to enable this feature")) {
870
- logger.warn("Branch protection was not enabled as it requires GitHub Pro for private repositories");
984
+ if (e.message.includes(
985
+ "Upgrade to GitHub Pro or make this repository public to enable this feature"
986
+ )) {
987
+ logger.warn(
988
+ "Branch protection was not enabled as it requires GitHub Pro for private repositories"
989
+ );
871
990
  } else {
872
991
  throw e;
873
992
  }
@@ -909,10 +1028,14 @@ async function getOctokitOptions(options) {
909
1028
  }
910
1029
  const githubCredentialsProvider = credentialsProvider != null ? credentialsProvider : integration.DefaultGithubCredentialsProvider.fromIntegrations(integrations);
911
1030
  const { token: credentialProviderToken } = await githubCredentialsProvider.getCredentials({
912
- url: `https://${host}/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}`
1031
+ url: `https://${host}/${encodeURIComponent(owner)}/${encodeURIComponent(
1032
+ repo
1033
+ )}`
913
1034
  });
914
1035
  if (!credentialProviderToken) {
915
- throw new errors.InputError(`No token available for host: ${host}, with owner ${owner}, and repo ${repo}`);
1036
+ throw new errors.InputError(
1037
+ `No token available for host: ${host}, with owner ${owner}, and repo ${repo}`
1038
+ );
916
1039
  }
917
1040
  return {
918
1041
  auth: credentialProviderToken,
@@ -949,9 +1072,13 @@ async function createGithubRepoWithCollaboratorsAndTopics(client, repo, owner, r
949
1072
  } catch (e) {
950
1073
  errors.assertError(e);
951
1074
  if (e.message === "Resource not accessible by integration") {
952
- logger.warn(`The GitHub app or token provided may not have the required permissions to create the ${user.data.type} repository ${owner}/${repo}.`);
1075
+ logger.warn(
1076
+ `The GitHub app or token provided may not have the required permissions to create the ${user.data.type} repository ${owner}/${repo}.`
1077
+ );
953
1078
  }
954
- throw new Error(`Failed to create the ${user.data.type} repository ${owner}/${repo}, ${e.message}`);
1079
+ throw new Error(
1080
+ `Failed to create the ${user.data.type} repository ${owner}/${repo}, ${e.message}`
1081
+ );
955
1082
  }
956
1083
  if (access == null ? void 0 : access.startsWith(`${owner}/`)) {
957
1084
  const [, team] = access.split("/");
@@ -992,7 +1119,9 @@ async function createGithubRepoWithCollaboratorsAndTopics(client, repo, owner, r
992
1119
  } catch (e) {
993
1120
  errors.assertError(e);
994
1121
  const name = extractCollaboratorName(collaborator);
995
- logger.warn(`Skipping ${collaborator.access} access for ${name}, ${e.message}`);
1122
+ logger.warn(
1123
+ `Skipping ${collaborator.access} access for ${name}, ${e.message}`
1124
+ );
996
1125
  }
997
1126
  }
998
1127
  }
@@ -1042,7 +1171,9 @@ async function initRepoPushAndProtect(remoteUrl, password, workspacePath, source
1042
1171
  });
1043
1172
  } catch (e) {
1044
1173
  errors.assertError(e);
1045
- logger.warn(`Skipping: default branch protection on '${repo}', ${e.message}`);
1174
+ logger.warn(
1175
+ `Skipping: default branch protection on '${repo}', ${e.message}`
1176
+ );
1046
1177
  }
1047
1178
  }
1048
1179
  }
@@ -1100,17 +1231,21 @@ function createGithubActionsDispatchAction(options) {
1100
1231
  workflowInputs,
1101
1232
  token: providedToken
1102
1233
  } = ctx.input;
1103
- ctx.logger.info(`Dispatching workflow ${workflowId} for repo ${repoUrl} on ${branchOrTagName}`);
1234
+ ctx.logger.info(
1235
+ `Dispatching workflow ${workflowId} for repo ${repoUrl} on ${branchOrTagName}`
1236
+ );
1104
1237
  const { owner, repo } = parseRepoUrl(repoUrl, integrations);
1105
1238
  if (!owner) {
1106
1239
  throw new errors.InputError("Invalid repository owner provided in repoUrl");
1107
1240
  }
1108
- const client = new octokit.Octokit(await getOctokitOptions({
1109
- integrations,
1110
- repoUrl,
1111
- credentialsProvider: githubCredentialsProvider,
1112
- token: providedToken
1113
- }));
1241
+ const client = new octokit.Octokit(
1242
+ await getOctokitOptions({
1243
+ integrations,
1244
+ repoUrl,
1245
+ credentialsProvider: githubCredentialsProvider,
1246
+ token: providedToken
1247
+ })
1248
+ );
1114
1249
  await client.rest.actions.createWorkflowDispatch({
1115
1250
  owner,
1116
1251
  repo,
@@ -1166,12 +1301,14 @@ function createGithubIssuesLabelAction(options) {
1166
1301
  if (!owner) {
1167
1302
  throw new errors.InputError("Invalid repository owner provided in repoUrl");
1168
1303
  }
1169
- const client = new octokit.Octokit(await getOctokitOptions({
1170
- integrations,
1171
- credentialsProvider: githubCredentialsProvider,
1172
- repoUrl,
1173
- token: providedToken
1174
- }));
1304
+ const client = new octokit.Octokit(
1305
+ await getOctokitOptions({
1306
+ integrations,
1307
+ credentialsProvider: githubCredentialsProvider,
1308
+ repoUrl,
1309
+ token: providedToken
1310
+ })
1311
+ );
1175
1312
  try {
1176
1313
  await client.rest.issues.addLabels({
1177
1314
  owner,
@@ -1181,7 +1318,9 @@ function createGithubIssuesLabelAction(options) {
1181
1318
  });
1182
1319
  } catch (e) {
1183
1320
  errors.assertError(e);
1184
- ctx.logger.warn(`Failed: adding labels to issue: '${number}' on repo: '${repo}', ${e.message}`);
1321
+ ctx.logger.warn(
1322
+ `Failed: adding labels to issue: '${number}' on repo: '${repo}', ${e.message}`
1323
+ );
1185
1324
  }
1186
1325
  }
1187
1326
  });
@@ -1380,7 +1519,21 @@ function createGithubRepoCreateAction(options) {
1380
1519
  if (!owner) {
1381
1520
  throw new errors.InputError("Invalid repository owner provided in repoUrl");
1382
1521
  }
1383
- const newRepo = await createGithubRepoWithCollaboratorsAndTopics(client, repo, owner, repoVisibility, description, deleteBranchOnMerge, allowMergeCommit, allowSquashMerge, allowRebaseMerge, access, collaborators, topics, ctx.logger);
1522
+ const newRepo = await createGithubRepoWithCollaboratorsAndTopics(
1523
+ client,
1524
+ repo,
1525
+ owner,
1526
+ repoVisibility,
1527
+ description,
1528
+ deleteBranchOnMerge,
1529
+ allowMergeCommit,
1530
+ allowSquashMerge,
1531
+ allowRebaseMerge,
1532
+ access,
1533
+ collaborators,
1534
+ topics,
1535
+ ctx.logger
1536
+ );
1384
1537
  ctx.output("remoteUrl", newRepo.clone_url);
1385
1538
  }
1386
1539
  });
@@ -1444,7 +1597,25 @@ function createGithubRepoPushAction(options) {
1444
1597
  const targetRepo = await client.rest.repos.get({ owner, repo });
1445
1598
  const remoteUrl = targetRepo.data.clone_url;
1446
1599
  const repoContentsUrl = `${targetRepo.data.html_url}/blob/${defaultBranch}`;
1447
- await initRepoPushAndProtect(remoteUrl, octokitOptions.auth, ctx.workspacePath, ctx.input.sourcePath, defaultBranch, protectDefaultBranch, protectEnforceAdmins, owner, client, repo, requireCodeOwnerReviews, requiredStatusCheckContexts, config, ctx.logger, gitCommitMessage, gitAuthorName, gitAuthorEmail);
1600
+ await initRepoPushAndProtect(
1601
+ remoteUrl,
1602
+ octokitOptions.auth,
1603
+ ctx.workspacePath,
1604
+ ctx.input.sourcePath,
1605
+ defaultBranch,
1606
+ protectDefaultBranch,
1607
+ protectEnforceAdmins,
1608
+ owner,
1609
+ client,
1610
+ repo,
1611
+ requireCodeOwnerReviews,
1612
+ requiredStatusCheckContexts,
1613
+ config,
1614
+ ctx.logger,
1615
+ gitCommitMessage,
1616
+ gitAuthorName,
1617
+ gitAuthorEmail
1618
+ );
1448
1619
  ctx.output("remoteUrl", remoteUrl);
1449
1620
  ctx.output("repoContentsUrl", repoContentsUrl);
1450
1621
  }
@@ -1536,12 +1707,14 @@ function createGithubWebhookAction(options) {
1536
1707
  if (!owner) {
1537
1708
  throw new errors.InputError("Invalid repository owner provided in repoUrl");
1538
1709
  }
1539
- const client = new octokit.Octokit(await getOctokitOptions({
1540
- integrations,
1541
- credentialsProvider: githubCredentialsProvider,
1542
- repoUrl,
1543
- token: providedToken
1544
- }));
1710
+ const client = new octokit.Octokit(
1711
+ await getOctokitOptions({
1712
+ integrations,
1713
+ credentialsProvider: githubCredentialsProvider,
1714
+ repoUrl,
1715
+ token: providedToken
1716
+ })
1717
+ );
1545
1718
  try {
1546
1719
  const insecure_ssl = insecureSsl ? "1" : "0";
1547
1720
  await client.rest.repos.createWebhook({
@@ -1559,7 +1732,9 @@ function createGithubWebhookAction(options) {
1559
1732
  ctx.logger.info(`Webhook '${webhookUrl}' created successfully`);
1560
1733
  } catch (e) {
1561
1734
  errors.assertError(e);
1562
- ctx.logger.warn(`Failed: create webhook '${webhookUrl}' on repo: '${repo}', ${e.message}`);
1735
+ ctx.logger.warn(
1736
+ `Failed: create webhook '${webhookUrl}' on repo: '${repo}', ${e.message}`
1737
+ );
1563
1738
  }
1564
1739
  }
1565
1740
  });
@@ -1638,13 +1813,20 @@ function createPublishAzureAction(options) {
1638
1813
  gitAuthorName,
1639
1814
  gitAuthorEmail
1640
1815
  } = ctx.input;
1641
- const { owner, repo, host, organization } = parseRepoUrl(repoUrl, integrations);
1816
+ const { owner, repo, host, organization } = parseRepoUrl(
1817
+ repoUrl,
1818
+ integrations
1819
+ );
1642
1820
  if (!organization) {
1643
- throw new errors.InputError(`Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing organization`);
1821
+ throw new errors.InputError(
1822
+ `Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing organization`
1823
+ );
1644
1824
  }
1645
1825
  const integrationConfig = integrations.azure.byHost(host);
1646
1826
  if (!integrationConfig) {
1647
- throw new errors.InputError(`No matching integration configuration for host ${host}, please check your integrations config`);
1827
+ throw new errors.InputError(
1828
+ `No matching integration configuration for host ${host}, please check your integrations config`
1829
+ );
1648
1830
  }
1649
1831
  if (!integrationConfig.config.token && !ctx.input.token) {
1650
1832
  throw new errors.InputError(`No token provided for Azure Integration ${host}`);
@@ -1656,12 +1838,16 @@ function createPublishAzureAction(options) {
1656
1838
  const createOptions = { name: repo };
1657
1839
  const returnedRepo = await client.createRepository(createOptions, owner);
1658
1840
  if (!returnedRepo) {
1659
- throw new errors.InputError(`Unable to create the repository with Organization ${organization}, Project ${owner} and Repo ${repo}.
1660
- Please make sure that both the Org and Project are typed corrected and exist.`);
1841
+ throw new errors.InputError(
1842
+ `Unable to create the repository with Organization ${organization}, Project ${owner} and Repo ${repo}.
1843
+ Please make sure that both the Org and Project are typed corrected and exist.`
1844
+ );
1661
1845
  }
1662
1846
  const remoteUrl = returnedRepo.remoteUrl;
1663
1847
  if (!remoteUrl) {
1664
- throw new errors.InputError("No remote URL returned from create repository for Azure");
1848
+ throw new errors.InputError(
1849
+ "No remote URL returned from create repository for Azure"
1850
+ );
1665
1851
  }
1666
1852
  const repoContentsUrl = remoteUrl;
1667
1853
  const gitAuthorInfo = {
@@ -1712,12 +1898,17 @@ const createBitbucketCloudRepository = async (opts) => {
1712
1898
  };
1713
1899
  let response;
1714
1900
  try {
1715
- response = await fetch__default["default"](`${apiBaseUrl}/repositories/${workspace}/${repo}`, options);
1901
+ response = await fetch__default["default"](
1902
+ `${apiBaseUrl}/repositories/${workspace}/${repo}`,
1903
+ options
1904
+ );
1716
1905
  } catch (e) {
1717
1906
  throw new Error(`Unable to create repository, ${e}`);
1718
1907
  }
1719
1908
  if (response.status !== 200) {
1720
- throw new Error(`Unable to create repository, ${response.status} ${response.statusText}, ${await response.text()}`);
1909
+ throw new Error(
1910
+ `Unable to create repository, ${response.status} ${response.statusText}, ${await response.text()}`
1911
+ );
1721
1912
  }
1722
1913
  const r = await response.json();
1723
1914
  let remoteUrl = "";
@@ -1757,7 +1948,9 @@ const createBitbucketServerRepository = async (opts) => {
1757
1948
  throw new Error(`Unable to create repository, ${e}`);
1758
1949
  }
1759
1950
  if (response.status !== 201) {
1760
- throw new Error(`Unable to create repository, ${response.status} ${response.statusText}, ${await response.text()}`);
1951
+ throw new Error(
1952
+ `Unable to create repository, ${response.status} ${response.statusText}, ${await response.text()}`
1953
+ );
1761
1954
  }
1762
1955
  const r = await response.json();
1763
1956
  let remoteUrl = "";
@@ -1769,15 +1962,20 @@ const createBitbucketServerRepository = async (opts) => {
1769
1962
  const repoContentsUrl = `${r.links.self[0].href}`;
1770
1963
  return { remoteUrl, repoContentsUrl };
1771
1964
  };
1772
- const getAuthorizationHeader$2 = (config) => {
1965
+ const getAuthorizationHeader$1 = (config) => {
1773
1966
  if (config.username && config.appPassword) {
1774
- const buffer = Buffer.from(`${config.username}:${config.appPassword}`, "utf8");
1967
+ const buffer = Buffer.from(
1968
+ `${config.username}:${config.appPassword}`,
1969
+ "utf8"
1970
+ );
1775
1971
  return `Basic ${buffer.toString("base64")}`;
1776
1972
  }
1777
1973
  if (config.token) {
1778
1974
  return `Bearer ${config.token}`;
1779
1975
  }
1780
- throw new Error(`Authorization has not been provided for Bitbucket. Please add either username + appPassword or token to the Integrations config`);
1976
+ throw new Error(
1977
+ `Authorization has not been provided for Bitbucket. Please add either username + appPassword or token to the Integrations config`
1978
+ );
1781
1979
  };
1782
1980
  const performEnableLFS$1 = async (opts) => {
1783
1981
  const { authorization, host, project, repo } = opts;
@@ -1787,9 +1985,14 @@ const performEnableLFS$1 = async (opts) => {
1787
1985
  Authorization: authorization
1788
1986
  }
1789
1987
  };
1790
- const { ok, status, statusText } = await fetch__default["default"](`https://${host}/rest/git-lfs/admin/projects/${project}/repos/${repo}/enabled`, options);
1988
+ const { ok, status, statusText } = await fetch__default["default"](
1989
+ `https://${host}/rest/git-lfs/admin/projects/${project}/repos/${repo}/enabled`,
1990
+ options
1991
+ );
1791
1992
  if (!ok)
1792
- throw new Error(`Failed to enable LFS in the repository, ${status}: ${statusText}`);
1993
+ throw new Error(
1994
+ `Failed to enable LFS in the repository, ${status}: ${statusText}`
1995
+ );
1793
1996
  };
1794
1997
  function createPublishBitbucketAction(options) {
1795
1998
  const { integrations, config } = options;
@@ -1867,7 +2070,9 @@ function createPublishBitbucketAction(options) {
1867
2070
  },
1868
2071
  async handler(ctx) {
1869
2072
  var _a;
1870
- ctx.logger.warn(`[Deprecated] Please migrate the use of action "publish:bitbucket" to "publish:bitbucketCloud" or "publish:bitbucketServer".`);
2073
+ ctx.logger.warn(
2074
+ `[Deprecated] Please migrate the use of action "publish:bitbucket" to "publish:bitbucketCloud" or "publish:bitbucketServer".`
2075
+ );
1871
2076
  const {
1872
2077
  repoUrl,
1873
2078
  description,
@@ -1878,24 +2083,35 @@ function createPublishBitbucketAction(options) {
1878
2083
  gitAuthorName,
1879
2084
  gitAuthorEmail
1880
2085
  } = ctx.input;
1881
- const { workspace, project, repo, host } = parseRepoUrl(repoUrl, integrations);
2086
+ const { workspace, project, repo, host } = parseRepoUrl(
2087
+ repoUrl,
2088
+ integrations
2089
+ );
1882
2090
  if (host === "bitbucket.org") {
1883
2091
  if (!workspace) {
1884
- throw new errors.InputError(`Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing workspace`);
2092
+ throw new errors.InputError(
2093
+ `Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing workspace`
2094
+ );
1885
2095
  }
1886
2096
  }
1887
2097
  if (!project) {
1888
- throw new errors.InputError(`Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing project`);
2098
+ throw new errors.InputError(
2099
+ `Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing project`
2100
+ );
1889
2101
  }
1890
2102
  const integrationConfig = integrations.bitbucket.byHost(host);
1891
2103
  if (!integrationConfig) {
1892
- throw new errors.InputError(`No matching integration configuration for host ${host}, please check your integrations config`);
2104
+ throw new errors.InputError(
2105
+ `No matching integration configuration for host ${host}, please check your integrations config`
2106
+ );
1893
2107
  }
1894
- const authorization = getAuthorizationHeader$2(ctx.input.token ? {
1895
- host: integrationConfig.config.host,
1896
- apiBaseUrl: integrationConfig.config.apiBaseUrl,
1897
- token: ctx.input.token
1898
- } : integrationConfig.config);
2108
+ const authorization = getAuthorizationHeader$1(
2109
+ ctx.input.token ? {
2110
+ host: integrationConfig.config.host,
2111
+ apiBaseUrl: integrationConfig.config.apiBaseUrl,
2112
+ token: ctx.input.token
2113
+ } : integrationConfig.config
2114
+ );
1899
2115
  const apiBaseUrl = integrationConfig.config.apiBaseUrl;
1900
2116
  const createMethod = host === "bitbucket.org" ? createBitbucketCloudRepository : createBitbucketServerRepository;
1901
2117
  const { remoteUrl, repoContentsUrl } = await createMethod({
@@ -1968,12 +2184,17 @@ const createRepository$1 = async (opts) => {
1968
2184
  };
1969
2185
  let response;
1970
2186
  try {
1971
- response = await fetch__default["default"](`${apiBaseUrl}/repositories/${workspace}/${repo}`, options);
2187
+ response = await fetch__default["default"](
2188
+ `${apiBaseUrl}/repositories/${workspace}/${repo}`,
2189
+ options
2190
+ );
1972
2191
  } catch (e) {
1973
2192
  throw new Error(`Unable to create repository, ${e}`);
1974
2193
  }
1975
2194
  if (response.status !== 200) {
1976
- throw new Error(`Unable to create repository, ${response.status} ${response.statusText}, ${await response.text()}`);
2195
+ throw new Error(
2196
+ `Unable to create repository, ${response.status} ${response.statusText}, ${await response.text()}`
2197
+ );
1977
2198
  }
1978
2199
  const r = await response.json();
1979
2200
  let remoteUrl = "";
@@ -1985,15 +2206,20 @@ const createRepository$1 = async (opts) => {
1985
2206
  const repoContentsUrl = `${r.links.html.href}/src/${mainBranch}`;
1986
2207
  return { remoteUrl, repoContentsUrl };
1987
2208
  };
1988
- const getAuthorizationHeader$1 = (config) => {
2209
+ const getAuthorizationHeader = (config) => {
1989
2210
  if (config.username && config.appPassword) {
1990
- const buffer = Buffer.from(`${config.username}:${config.appPassword}`, "utf8");
2211
+ const buffer = Buffer.from(
2212
+ `${config.username}:${config.appPassword}`,
2213
+ "utf8"
2214
+ );
1991
2215
  return `Basic ${buffer.toString("base64")}`;
1992
2216
  }
1993
2217
  if (config.token) {
1994
2218
  return `Bearer ${config.token}`;
1995
2219
  }
1996
- throw new Error(`Authorization has not been provided for Bitbucket Cloud. Please add either username + appPassword to the Integrations config or a user login auth token`);
2220
+ throw new Error(
2221
+ `Authorization has not been provided for Bitbucket Cloud. Please add either username + appPassword to the Integrations config or a user login auth token`
2222
+ );
1997
2223
  };
1998
2224
  function createPublishBitbucketCloudAction(options) {
1999
2225
  const { integrations, config } = options;
@@ -2056,18 +2282,29 @@ function createPublishBitbucketCloudAction(options) {
2056
2282
  defaultBranch = "master",
2057
2283
  repoVisibility = "private"
2058
2284
  } = ctx.input;
2059
- const { workspace, project, repo, host } = parseRepoUrl(repoUrl, integrations);
2285
+ const { workspace, project, repo, host } = parseRepoUrl(
2286
+ repoUrl,
2287
+ integrations
2288
+ );
2060
2289
  if (!workspace) {
2061
- throw new errors.InputError(`Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing workspace`);
2290
+ throw new errors.InputError(
2291
+ `Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing workspace`
2292
+ );
2062
2293
  }
2063
2294
  if (!project) {
2064
- throw new errors.InputError(`Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing project`);
2295
+ throw new errors.InputError(
2296
+ `Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing project`
2297
+ );
2065
2298
  }
2066
2299
  const integrationConfig = integrations.bitbucketCloud.byHost(host);
2067
2300
  if (!integrationConfig) {
2068
- throw new errors.InputError(`No matching integration configuration for host ${host}, please check your integrations config`);
2301
+ throw new errors.InputError(
2302
+ `No matching integration configuration for host ${host}, please check your integrations config`
2303
+ );
2069
2304
  }
2070
- const authorization = getAuthorizationHeader$1(ctx.input.token ? { token: ctx.input.token } : integrationConfig.config);
2305
+ const authorization = getAuthorizationHeader(
2306
+ ctx.input.token ? { token: ctx.input.token } : integrationConfig.config
2307
+ );
2071
2308
  const apiBaseUrl = integrationConfig.config.apiBaseUrl;
2072
2309
  const { remoteUrl, repoContentsUrl } = await createRepository$1({
2073
2310
  authorization,
@@ -2091,7 +2328,9 @@ function createPublishBitbucketCloudAction(options) {
2091
2328
  };
2092
2329
  } else {
2093
2330
  if (!integrationConfig.config.username || !integrationConfig.config.appPassword) {
2094
- throw new Error("Credentials for Bitbucket Cloud integration required for this action.");
2331
+ throw new Error(
2332
+ "Credentials for Bitbucket Cloud integration required for this action."
2333
+ );
2095
2334
  }
2096
2335
  auth = {
2097
2336
  username: integrationConfig.config.username,
@@ -2104,7 +2343,9 @@ function createPublishBitbucketCloudAction(options) {
2104
2343
  auth,
2105
2344
  defaultBranch,
2106
2345
  logger: ctx.logger,
2107
- commitMessage: config.getOptionalString("scaffolder.defaultCommitMessage"),
2346
+ commitMessage: config.getOptionalString(
2347
+ "scaffolder.defaultCommitMessage"
2348
+ ),
2108
2349
  gitAuthorInfo
2109
2350
  });
2110
2351
  ctx.output("remoteUrl", remoteUrl);
@@ -2141,7 +2382,9 @@ const createRepository = async (opts) => {
2141
2382
  throw new Error(`Unable to create repository, ${e}`);
2142
2383
  }
2143
2384
  if (response.status !== 201) {
2144
- throw new Error(`Unable to create repository, ${response.status} ${response.statusText}, ${await response.text()}`);
2385
+ throw new Error(
2386
+ `Unable to create repository, ${response.status} ${response.statusText}, ${await response.text()}`
2387
+ );
2145
2388
  }
2146
2389
  const r = await response.json();
2147
2390
  let remoteUrl = "";
@@ -2153,9 +2396,6 @@ const createRepository = async (opts) => {
2153
2396
  const repoContentsUrl = `${r.links.self[0].href}`;
2154
2397
  return { remoteUrl, repoContentsUrl };
2155
2398
  };
2156
- const getAuthorizationHeader = (config) => {
2157
- return `Bearer ${config.token}`;
2158
- };
2159
2399
  const performEnableLFS = async (opts) => {
2160
2400
  const { authorization, host, project, repo } = opts;
2161
2401
  const options = {
@@ -2164,9 +2404,14 @@ const performEnableLFS = async (opts) => {
2164
2404
  Authorization: authorization
2165
2405
  }
2166
2406
  };
2167
- const { ok, status, statusText } = await fetch__default["default"](`https://${host}/rest/git-lfs/admin/projects/${project}/repos/${repo}/enabled`, options);
2407
+ const { ok, status, statusText } = await fetch__default["default"](
2408
+ `https://${host}/rest/git-lfs/admin/projects/${project}/repos/${repo}/enabled`,
2409
+ options
2410
+ );
2168
2411
  if (!ok)
2169
- throw new Error(`Failed to enable LFS in the repository, ${status}: ${statusText}`);
2412
+ throw new Error(
2413
+ `Failed to enable LFS in the repository, ${status}: ${statusText}`
2414
+ );
2170
2415
  };
2171
2416
  function createPublishBitbucketServerAction(options) {
2172
2417
  const { integrations, config } = options;
@@ -2238,17 +2483,28 @@ function createPublishBitbucketServerAction(options) {
2238
2483
  } = ctx.input;
2239
2484
  const { project, repo, host } = parseRepoUrl(repoUrl, integrations);
2240
2485
  if (!project) {
2241
- throw new errors.InputError(`Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing project`);
2486
+ throw new errors.InputError(
2487
+ `Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing project`
2488
+ );
2242
2489
  }
2243
2490
  const integrationConfig = integrations.bitbucketServer.byHost(host);
2244
2491
  if (!integrationConfig) {
2245
- throw new errors.InputError(`No matching integration configuration for host ${host}, please check your integrations config`);
2492
+ throw new errors.InputError(
2493
+ `No matching integration configuration for host ${host}, please check your integrations config`
2494
+ );
2246
2495
  }
2247
2496
  const token = (_a = ctx.input.token) != null ? _a : integrationConfig.config.token;
2248
- if (!token) {
2249
- throw new Error(`Authorization has not been provided for ${integrationConfig.config.host}. Please add either token to the Integrations config or a user login auth token`);
2497
+ const authConfig = {
2498
+ ...integrationConfig.config,
2499
+ ...{ token }
2500
+ };
2501
+ const reqOpts = integration.getBitbucketServerRequestOptions(authConfig);
2502
+ const authorization = reqOpts.headers.Authorization;
2503
+ if (!authorization) {
2504
+ throw new Error(
2505
+ `Authorization has not been provided for ${integrationConfig.config.host}. Please add either (a) a user login auth token, or (b) a token or (c) username + password to the integration config.`
2506
+ );
2250
2507
  }
2251
- const authorization = getAuthorizationHeader({ token });
2252
2508
  const apiBaseUrl = integrationConfig.config.apiBaseUrl;
2253
2509
  const { remoteUrl, repoContentsUrl } = await createRepository({
2254
2510
  authorization,
@@ -2262,9 +2518,11 @@ function createPublishBitbucketServerAction(options) {
2262
2518
  name: config.getOptionalString("scaffolder.defaultAuthor.name"),
2263
2519
  email: config.getOptionalString("scaffolder.defaultAuthor.email")
2264
2520
  };
2265
- const auth = {
2266
- username: "x-token-auth",
2267
- password: token
2521
+ const auth = authConfig.token ? {
2522
+ token
2523
+ } : {
2524
+ username: authConfig.username,
2525
+ password: authConfig.password
2268
2526
  };
2269
2527
  await initRepoAndPush({
2270
2528
  dir: getRepoSourceDirectory(ctx.workspacePath, ctx.input.sourcePath),
@@ -2272,7 +2530,9 @@ function createPublishBitbucketServerAction(options) {
2272
2530
  auth,
2273
2531
  defaultBranch,
2274
2532
  logger: ctx.logger,
2275
- commitMessage: config.getOptionalString("scaffolder.defaultCommitMessage"),
2533
+ commitMessage: config.getOptionalString(
2534
+ "scaffolder.defaultCommitMessage"
2535
+ ),
2276
2536
  gitAuthorInfo
2277
2537
  });
2278
2538
  if (enableLFS) {
@@ -2327,9 +2587,14 @@ const createGerritProject = async (config, options) => {
2327
2587
  "Content-Type": "application/json"
2328
2588
  }
2329
2589
  };
2330
- const response = await fetch__default["default"](`${config.baseUrl}/a/projects/${encodeURIComponent(projectName)}`, fetchOptions);
2590
+ const response = await fetch__default["default"](
2591
+ `${config.baseUrl}/a/projects/${encodeURIComponent(projectName)}`,
2592
+ fetchOptions
2593
+ );
2331
2594
  if (response.status !== 201) {
2332
- throw new Error(`Unable to create repository, ${response.status} ${response.statusText}, ${await response.text()}`);
2595
+ throw new Error(
2596
+ `Unable to create repository, ${response.status} ${response.statusText}, ${await response.text()}`
2597
+ );
2333
2598
  }
2334
2599
  };
2335
2600
  const generateCommitMessage = (config, commitSubject) => {
@@ -2408,13 +2673,20 @@ function createPublishGerritAction(options) {
2408
2673
  gitCommitMessage = "initial commit",
2409
2674
  sourcePath
2410
2675
  } = ctx.input;
2411
- const { repo, host, owner, workspace } = parseRepoUrl(repoUrl, integrations);
2676
+ const { repo, host, owner, workspace } = parseRepoUrl(
2677
+ repoUrl,
2678
+ integrations
2679
+ );
2412
2680
  const integrationConfig = integrations.gerrit.byHost(host);
2413
2681
  if (!integrationConfig) {
2414
- throw new errors.InputError(`No matching integration configuration for host ${host}, please check your integrations config`);
2682
+ throw new errors.InputError(
2683
+ `No matching integration configuration for host ${host}, please check your integrations config`
2684
+ );
2415
2685
  }
2416
2686
  if (!workspace) {
2417
- throw new errors.InputError(`Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing workspace`);
2687
+ throw new errors.InputError(
2688
+ `Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing workspace`
2689
+ );
2418
2690
  }
2419
2691
  await createGerritProject(integrationConfig.config, {
2420
2692
  description,
@@ -2447,6 +2719,115 @@ function createPublishGerritAction(options) {
2447
2719
  });
2448
2720
  }
2449
2721
 
2722
+ const generateGerritChangeId = () => {
2723
+ const changeId = crypto__default["default"].randomBytes(20).toString("hex");
2724
+ return `I${changeId}`;
2725
+ };
2726
+ function createPublishGerritReviewAction(options) {
2727
+ const { integrations, config } = options;
2728
+ return createTemplateAction({
2729
+ id: "publish:gerrit:review",
2730
+ description: "Creates a new Gerrit review.",
2731
+ schema: {
2732
+ input: {
2733
+ type: "object",
2734
+ required: ["repoUrl", "gitCommitMessage"],
2735
+ properties: {
2736
+ repoUrl: {
2737
+ title: "Repository Location",
2738
+ type: "string"
2739
+ },
2740
+ branch: {
2741
+ title: "Repository branch",
2742
+ type: "string",
2743
+ description: "Branch of the repository the review will be created on"
2744
+ },
2745
+ sourcePath: {
2746
+ type: "string",
2747
+ title: "Working Subdirectory",
2748
+ description: "Subdirectory of working directory containing the repository"
2749
+ },
2750
+ gitCommitMessage: {
2751
+ title: "Git Commit Message",
2752
+ type: "string",
2753
+ description: `Sets the commit message on the repository.`
2754
+ },
2755
+ gitAuthorName: {
2756
+ title: "Default Author Name",
2757
+ type: "string",
2758
+ description: `Sets the default author name for the commit. The default value is 'Scaffolder'`
2759
+ },
2760
+ gitAuthorEmail: {
2761
+ title: "Default Author Email",
2762
+ type: "string",
2763
+ description: `Sets the default author email for the commit.`
2764
+ }
2765
+ }
2766
+ },
2767
+ output: {
2768
+ type: "object",
2769
+ properties: {
2770
+ reviewUrl: {
2771
+ title: "A URL to the review",
2772
+ type: "string"
2773
+ },
2774
+ repoContentsUrl: {
2775
+ title: "A URL to the root of the repository",
2776
+ type: "string"
2777
+ }
2778
+ }
2779
+ }
2780
+ },
2781
+ async handler(ctx) {
2782
+ var _a;
2783
+ const {
2784
+ repoUrl,
2785
+ branch = "master",
2786
+ sourcePath,
2787
+ gitAuthorName,
2788
+ gitAuthorEmail,
2789
+ gitCommitMessage
2790
+ } = ctx.input;
2791
+ const { host, repo } = parseRepoUrl(repoUrl, integrations);
2792
+ if (!gitCommitMessage) {
2793
+ throw new errors.InputError(`Missing gitCommitMessage input`);
2794
+ }
2795
+ const integrationConfig = integrations.gerrit.byHost(host);
2796
+ if (!integrationConfig) {
2797
+ throw new errors.InputError(
2798
+ `No matching integration configuration for host ${host}, please check your integrations config`
2799
+ );
2800
+ }
2801
+ const auth = {
2802
+ username: integrationConfig.config.username,
2803
+ password: integrationConfig.config.password
2804
+ };
2805
+ const gitAuthorInfo = {
2806
+ name: gitAuthorName ? gitAuthorName : config.getOptionalString("scaffolder.defaultAuthor.name"),
2807
+ email: gitAuthorEmail ? gitAuthorEmail : config.getOptionalString("scaffolder.defaultAuthor.email")
2808
+ };
2809
+ const changeId = generateGerritChangeId();
2810
+ const commitMessage = `${gitCommitMessage}
2811
+
2812
+ Change-Id: ${changeId}`;
2813
+ await commitAndPushRepo({
2814
+ dir: getRepoSourceDirectory(ctx.workspacePath, sourcePath),
2815
+ auth,
2816
+ logger: ctx.logger,
2817
+ commitMessage,
2818
+ gitAuthorInfo,
2819
+ branch,
2820
+ remoteRef: `refs/for/${branch}`
2821
+ });
2822
+ const repoContentsUrl = `${integrationConfig.config.gitilesBaseUrl}/${repo}/+/refs/heads/${branch}`;
2823
+ const reviewUrl = `${integrationConfig.config.baseUrl}/#/q/${changeId}`;
2824
+ (_a = ctx.logger) == null ? void 0 : _a.info(`Review available on ${reviewUrl}`);
2825
+ ctx.output("repoContentsUrl", repoContentsUrl);
2826
+ ctx.output("reviewUrl", reviewUrl);
2827
+ }
2828
+ });
2829
+ }
2830
+
2450
2831
  function createPublishGithubAction(options) {
2451
2832
  const { integrations, config, githubCredentialsProvider } = options;
2452
2833
  return createTemplateAction({
@@ -2520,10 +2901,42 @@ function createPublishGithubAction(options) {
2520
2901
  if (!owner) {
2521
2902
  throw new errors.InputError("Invalid repository owner provided in repoUrl");
2522
2903
  }
2523
- const newRepo = await createGithubRepoWithCollaboratorsAndTopics(client, repo, owner, repoVisibility, description, deleteBranchOnMerge, allowMergeCommit, allowSquashMerge, allowRebaseMerge, access, collaborators, topics, ctx.logger);
2904
+ const newRepo = await createGithubRepoWithCollaboratorsAndTopics(
2905
+ client,
2906
+ repo,
2907
+ owner,
2908
+ repoVisibility,
2909
+ description,
2910
+ deleteBranchOnMerge,
2911
+ allowMergeCommit,
2912
+ allowSquashMerge,
2913
+ allowRebaseMerge,
2914
+ access,
2915
+ collaborators,
2916
+ topics,
2917
+ ctx.logger
2918
+ );
2524
2919
  const remoteUrl = newRepo.clone_url;
2525
2920
  const repoContentsUrl = `${newRepo.html_url}/blob/${defaultBranch}`;
2526
- await initRepoPushAndProtect(remoteUrl, octokitOptions.auth, ctx.workspacePath, ctx.input.sourcePath, defaultBranch, protectDefaultBranch, protectEnforceAdmins, owner, client, repo, requireCodeOwnerReviews, requiredStatusCheckContexts, config, ctx.logger, gitCommitMessage, gitAuthorName, gitAuthorEmail);
2921
+ await initRepoPushAndProtect(
2922
+ remoteUrl,
2923
+ octokitOptions.auth,
2924
+ ctx.workspacePath,
2925
+ ctx.input.sourcePath,
2926
+ defaultBranch,
2927
+ protectDefaultBranch,
2928
+ protectEnforceAdmins,
2929
+ owner,
2930
+ client,
2931
+ repo,
2932
+ requireCodeOwnerReviews,
2933
+ requiredStatusCheckContexts,
2934
+ config,
2935
+ ctx.logger,
2936
+ gitCommitMessage,
2937
+ gitAuthorName,
2938
+ gitAuthorEmail
2939
+ );
2527
2940
  ctx.output("remoteUrl", remoteUrl);
2528
2941
  ctx.output("repoContentsUrl", repoContentsUrl);
2529
2942
  }
@@ -2550,11 +2963,15 @@ async function serializeDirectoryContents(sourcePath, options) {
2550
2963
  stats: true
2551
2964
  });
2552
2965
  const limiter = limiterFactory__default["default"](10);
2553
- return Promise.all(paths.map(async ({ path: path$1, stats }) => ({
2554
- path: path$1,
2555
- content: await limiter(async () => fs__default["default"].readFile(path.join(sourcePath, path$1))),
2556
- executable: isExecutable(stats == null ? void 0 : stats.mode)
2557
- })));
2966
+ return Promise.all(
2967
+ paths.map(async ({ path: path$1, stats }) => ({
2968
+ path: path$1,
2969
+ content: await limiter(
2970
+ async () => fs__default["default"].readFile(path.join(sourcePath, path$1))
2971
+ ),
2972
+ executable: isExecutable(stats == null ? void 0 : stats.mode)
2973
+ }))
2974
+ );
2558
2975
  }
2559
2976
 
2560
2977
  async function deserializeDirectoryContents(targetPath, files) {
@@ -2575,7 +2992,9 @@ const defaultClientFactory = async ({
2575
2992
  host = "github.com",
2576
2993
  token: providedToken
2577
2994
  }) => {
2578
- const [encodedHost, encodedOwner, encodedRepo] = [host, owner, repo].map(encodeURIComponent);
2995
+ const [encodedHost, encodedOwner, encodedRepo] = [host, owner, repo].map(
2996
+ encodeURIComponent
2997
+ );
2579
2998
  const octokitOptions = await getOctokitOptions({
2580
2999
  integrations,
2581
3000
  credentialsProvider: githubCredentialsProvider,
@@ -2636,6 +3055,22 @@ const createPublishGithubPullRequestAction = ({
2636
3055
  title: "Authentication Token",
2637
3056
  type: "string",
2638
3057
  description: "The token to use for authorization to GitHub"
3058
+ },
3059
+ reviewers: {
3060
+ title: "Pull Request Reviewers",
3061
+ type: "array",
3062
+ items: {
3063
+ type: "string"
3064
+ },
3065
+ description: "The users that will be added as reviewers to the pull request"
3066
+ },
3067
+ teamReviewers: {
3068
+ title: "Pull Request Team Reviewers",
3069
+ type: "array",
3070
+ items: {
3071
+ type: "string"
3072
+ },
3073
+ description: "The teams that will be added as reviewers to the pull request"
2639
3074
  }
2640
3075
  }
2641
3076
  },
@@ -2665,11 +3100,15 @@ const createPublishGithubPullRequestAction = ({
2665
3100
  draft,
2666
3101
  targetPath,
2667
3102
  sourcePath,
2668
- token: providedToken
3103
+ token: providedToken,
3104
+ reviewers,
3105
+ teamReviewers
2669
3106
  } = ctx.input;
2670
3107
  const { owner, repo, host } = parseRepoUrl(repoUrl, integrations);
2671
3108
  if (!owner) {
2672
- throw new errors.InputError(`No owner provided for host: ${host}, and repo ${repo}`);
3109
+ throw new errors.InputError(
3110
+ `No owner provided for host: ${host}, and repo ${repo}`
3111
+ );
2673
3112
  }
2674
3113
  const client = await clientFactory({
2675
3114
  integrations,
@@ -2683,14 +3122,16 @@ const createPublishGithubPullRequestAction = ({
2683
3122
  const directoryContents = await serializeDirectoryContents(fileRoot, {
2684
3123
  gitignore: true
2685
3124
  });
2686
- const files = Object.fromEntries(directoryContents.map((file) => [
2687
- targetPath ? path__default["default"].posix.join(targetPath, file.path) : file.path,
2688
- {
2689
- mode: file.executable ? "100755" : "100644",
2690
- encoding: "base64",
2691
- content: file.content.toString("base64")
2692
- }
2693
- ]));
3125
+ const files = Object.fromEntries(
3126
+ directoryContents.map((file) => [
3127
+ targetPath ? path__default["default"].posix.join(targetPath, file.path) : file.path,
3128
+ {
3129
+ mode: file.executable ? "100755" : "100644",
3130
+ encoding: "base64",
3131
+ content: file.content.toString("base64")
3132
+ }
3133
+ ])
3134
+ );
2694
3135
  try {
2695
3136
  const response = await client.createPullRequest({
2696
3137
  owner,
@@ -2709,13 +3150,46 @@ const createPublishGithubPullRequestAction = ({
2709
3150
  if (!response) {
2710
3151
  throw new GithubResponseError("null response from Github");
2711
3152
  }
3153
+ const pullRequestNumber = response.data.number;
3154
+ if (reviewers || teamReviewers) {
3155
+ const pullRequest = { owner, repo, number: pullRequestNumber };
3156
+ await requestReviewersOnPullRequest(
3157
+ pullRequest,
3158
+ reviewers,
3159
+ teamReviewers,
3160
+ client,
3161
+ ctx.logger
3162
+ );
3163
+ }
2712
3164
  ctx.output("remoteUrl", response.data.html_url);
2713
- ctx.output("pullRequestNumber", response.data.number);
3165
+ ctx.output("pullRequestNumber", pullRequestNumber);
2714
3166
  } catch (e) {
2715
3167
  throw new GithubResponseError("Pull request creation failed", e);
2716
3168
  }
2717
3169
  }
2718
3170
  });
3171
+ async function requestReviewersOnPullRequest(pr, reviewers, teamReviewers, client, logger) {
3172
+ var _a, _b, _c, _d;
3173
+ try {
3174
+ const result = await client.rest.pulls.requestReviewers({
3175
+ owner: pr.owner,
3176
+ repo: pr.repo,
3177
+ pull_number: pr.number,
3178
+ reviewers,
3179
+ team_reviewers: teamReviewers
3180
+ });
3181
+ const addedUsers = (_b = (_a = result.data.requested_reviewers) == null ? void 0 : _a.join(", ")) != null ? _b : "";
3182
+ const addedTeams = (_d = (_c = result.data.requested_teams) == null ? void 0 : _c.join(", ")) != null ? _d : "";
3183
+ logger.info(
3184
+ `Added users [${addedUsers}] and teams [${addedTeams}] as reviewers to Pull request ${pr.number}`
3185
+ );
3186
+ } catch (e) {
3187
+ logger.error(
3188
+ `Failure when adding reviewers to Pull request ${pr.number}`,
3189
+ e
3190
+ );
3191
+ }
3192
+ }
2719
3193
  };
2720
3194
 
2721
3195
  function createPublishGitlabAction(options) {
@@ -2800,11 +3274,15 @@ function createPublishGitlabAction(options) {
2800
3274
  } = ctx.input;
2801
3275
  const { owner, repo, host } = parseRepoUrl(repoUrl, integrations);
2802
3276
  if (!owner) {
2803
- throw new errors.InputError(`No owner provided for host: ${host}, and repo ${repo}`);
3277
+ throw new errors.InputError(
3278
+ `No owner provided for host: ${host}, and repo ${repo}`
3279
+ );
2804
3280
  }
2805
3281
  const integrationConfig = integrations.gitlab.byHost(host);
2806
3282
  if (!integrationConfig) {
2807
- throw new errors.InputError(`No matching integration configuration for host ${host}, please check your integrations config`);
3283
+ throw new errors.InputError(
3284
+ `No matching integration configuration for host ${host}, please check your integrations config`
3285
+ );
2808
3286
  }
2809
3287
  if (!integrationConfig.config.token && !ctx.input.token) {
2810
3288
  throw new errors.InputError(`No token available for host ${host}`);
@@ -2900,6 +3378,12 @@ const createPublishGitlabMergeRequestAction = (options) => {
2900
3378
  type: "string",
2901
3379
  description: "The token to use for authorization to GitLab"
2902
3380
  },
3381
+ commitAction: {
3382
+ title: "Commit action",
3383
+ type: "string",
3384
+ enum: ["create", "update", "delete"],
3385
+ description: "The action to be used for git commit. Defaults to create."
3386
+ },
2903
3387
  removeSourceBranch: {
2904
3388
  title: "Delete source branch",
2905
3389
  type: "boolean",
@@ -2944,7 +3428,9 @@ const createPublishGitlabMergeRequestAction = (options) => {
2944
3428
  const integrationConfig = integrations.gitlab.byHost(host);
2945
3429
  const destinationBranch = ctx.input.branchName;
2946
3430
  if (!integrationConfig) {
2947
- throw new errors.InputError(`No matching integration configuration for host ${host}, please check your integrations config`);
3431
+ throw new errors.InputError(
3432
+ `No matching integration configuration for host ${host}, please check your integrations config`
3433
+ );
2948
3434
  }
2949
3435
  if (!integrationConfig.config.token && !ctx.input.token) {
2950
3436
  throw new errors.InputError(`No token available for host ${host}`);
@@ -2962,38 +3448,63 @@ const createPublishGitlabMergeRequestAction = (options) => {
2962
3448
  const assigneeUser = await api.Users.username(assignee);
2963
3449
  assigneeId = assigneeUser[0].id;
2964
3450
  } catch (e) {
2965
- ctx.logger.warn(`Failed to find gitlab user id for ${assignee}: ${e}. Proceeding with MR creation without an assignee.`);
3451
+ ctx.logger.warn(
3452
+ `Failed to find gitlab user id for ${assignee}: ${e}. Proceeding with MR creation without an assignee.`
3453
+ );
2966
3454
  }
2967
3455
  }
2968
- const targetPath = backendCommon.resolveSafeChildPath(ctx.workspacePath, ctx.input.targetPath);
3456
+ const targetPath = backendCommon.resolveSafeChildPath(
3457
+ ctx.workspacePath,
3458
+ ctx.input.targetPath
3459
+ );
2969
3460
  const fileContents = await serializeDirectoryContents(targetPath, {
2970
3461
  gitignore: true
2971
3462
  });
2972
- const actions = fileContents.map((file) => ({
2973
- action: "create",
2974
- filePath: path__default["default"].posix.join(ctx.input.targetPath, file.path),
2975
- encoding: "base64",
2976
- content: file.content.toString("base64"),
2977
- execute_filemode: file.executable
2978
- }));
3463
+ const actions = fileContents.map((file) => {
3464
+ var _a2;
3465
+ return {
3466
+ action: (_a2 = ctx.input.commitAction) != null ? _a2 : "create",
3467
+ filePath: path__default["default"].posix.join(ctx.input.targetPath, file.path),
3468
+ encoding: "base64",
3469
+ content: file.content.toString("base64"),
3470
+ execute_filemode: file.executable
3471
+ };
3472
+ });
2979
3473
  const projects = await api.Projects.show(projectPath);
2980
3474
  const { default_branch: defaultBranch } = projects;
2981
3475
  try {
2982
- await api.Branches.create(projectPath, destinationBranch, String(defaultBranch));
3476
+ await api.Branches.create(
3477
+ projectPath,
3478
+ destinationBranch,
3479
+ String(defaultBranch)
3480
+ );
2983
3481
  } catch (e) {
2984
3482
  throw new errors.InputError(`The branch creation failed ${e}`);
2985
3483
  }
2986
3484
  try {
2987
- await api.Commits.create(projectPath, destinationBranch, ctx.input.title, actions);
3485
+ await api.Commits.create(
3486
+ projectPath,
3487
+ destinationBranch,
3488
+ ctx.input.title,
3489
+ actions
3490
+ );
2988
3491
  } catch (e) {
2989
- throw new errors.InputError(`Committing the changes to ${destinationBranch} failed ${e}`);
3492
+ throw new errors.InputError(
3493
+ `Committing the changes to ${destinationBranch} failed ${e}`
3494
+ );
2990
3495
  }
2991
3496
  try {
2992
- const mergeRequestUrl = await api.MergeRequests.create(projectPath, destinationBranch, String(defaultBranch), ctx.input.title, {
2993
- description: ctx.input.description,
2994
- removeSourceBranch: ctx.input.removeSourceBranch ? ctx.input.removeSourceBranch : false,
2995
- assigneeId
2996
- }).then((mergeRequest) => {
3497
+ const mergeRequestUrl = await api.MergeRequests.create(
3498
+ projectPath,
3499
+ destinationBranch,
3500
+ String(defaultBranch),
3501
+ ctx.input.title,
3502
+ {
3503
+ description: ctx.input.description,
3504
+ removeSourceBranch: ctx.input.removeSourceBranch ? ctx.input.removeSourceBranch : false,
3505
+ assigneeId
3506
+ }
3507
+ ).then((mergeRequest) => {
2997
3508
  return mergeRequest.web_url;
2998
3509
  });
2999
3510
  ctx.output("projectid", projectPath);
@@ -3029,6 +3540,10 @@ const createBuiltinActions = (options) => {
3029
3540
  integrations,
3030
3541
  config
3031
3542
  }),
3543
+ createPublishGerritReviewAction({
3544
+ integrations,
3545
+ config
3546
+ }),
3032
3547
  createPublishGithubAction({
3033
3548
  integrations,
3034
3549
  config,
@@ -3097,14 +3612,18 @@ class TemplateActionRegistry {
3097
3612
  }
3098
3613
  register(action) {
3099
3614
  if (this.actions.has(action.id)) {
3100
- throw new errors.ConflictError(`Template action with ID '${action.id}' has already been registered`);
3615
+ throw new errors.ConflictError(
3616
+ `Template action with ID '${action.id}' has already been registered`
3617
+ );
3101
3618
  }
3102
3619
  this.actions.set(action.id, action);
3103
3620
  }
3104
3621
  get(actionId) {
3105
3622
  const action = this.actions.get(actionId);
3106
3623
  if (!action) {
3107
- throw new errors.NotFoundError(`Template action with ID '${actionId}' is not registered.`);
3624
+ throw new errors.NotFoundError(
3625
+ `Template action with ID '${actionId}' is not registered.`
3626
+ );
3108
3627
  }
3109
3628
  return action;
3110
3629
  }
@@ -3113,7 +3632,10 @@ class TemplateActionRegistry {
3113
3632
  }
3114
3633
  }
3115
3634
 
3116
- const migrationsDir = backendCommon.resolvePackagePath("@backstage/plugin-scaffolder-backend", "migrations");
3635
+ const migrationsDir = backendCommon.resolvePackagePath(
3636
+ "@backstage/plugin-scaffolder-backend",
3637
+ "migrations"
3638
+ );
3117
3639
  const parseSqlDateToIsoString = (input) => {
3118
3640
  if (typeof input === "string") {
3119
3641
  return luxon.DateTime.fromSQL(input, { zone: "UTC" }).toISO();
@@ -3228,10 +3750,14 @@ class DatabaseTaskStore {
3228
3750
  }
3229
3751
  }
3230
3752
  async listStaleTasks({ timeoutS }) {
3231
- const rawRows = await this.db("tasks").where("status", "processing").andWhere("last_heartbeat_at", "<=", this.db.client.config.client.includes("sqlite3") ? this.db.raw(`datetime('now', ?)`, [`-${timeoutS} seconds`]) : this.db.raw(`dateadd('second', ?, ?)`, [
3232
- `-${timeoutS}`,
3233
- this.db.fn.now()
3234
- ]));
3753
+ const rawRows = await this.db("tasks").where("status", "processing").andWhere(
3754
+ "last_heartbeat_at",
3755
+ "<=",
3756
+ this.db.client.config.client.includes("sqlite3") ? this.db.raw(`datetime('now', ?)`, [`-${timeoutS} seconds`]) : this.db.raw(`dateadd('second', ?, ?)`, [
3757
+ `-${timeoutS}`,
3758
+ this.db.fn.now()
3759
+ ])
3760
+ );
3235
3761
  const tasks = rawRows.map((row) => ({
3236
3762
  taskId: row.id
3237
3763
  }));
@@ -3246,7 +3772,9 @@ class DatabaseTaskStore {
3246
3772
  if (status === "failed" || status === "completed") {
3247
3773
  oldStatus = "processing";
3248
3774
  } else {
3249
- throw new Error(`Invalid status update of run '${taskId}' to status '${status}'`);
3775
+ throw new Error(
3776
+ `Invalid status update of run '${taskId}' to status '${status}'`
3777
+ );
3250
3778
  }
3251
3779
  await this.db.transaction(async (tx) => {
3252
3780
  const [task] = await tx("tasks").where({
@@ -3256,7 +3784,9 @@ class DatabaseTaskStore {
3256
3784
  throw new Error(`No task with taskId ${taskId} found`);
3257
3785
  }
3258
3786
  if (task.status !== oldStatus) {
3259
- throw new errors.ConflictError(`Refusing to update status of run '${taskId}' to status '${status}' as it is currently '${task.status}', expected '${oldStatus}'`);
3787
+ throw new errors.ConflictError(
3788
+ `Refusing to update status of run '${taskId}' to status '${status}' as it is currently '${task.status}', expected '${oldStatus}'`
3789
+ );
3260
3790
  }
3261
3791
  const updateCount = await tx("tasks").where({
3262
3792
  id: taskId,
@@ -3265,7 +3795,9 @@ class DatabaseTaskStore {
3265
3795
  status
3266
3796
  });
3267
3797
  if (updateCount !== 1) {
3268
- throw new errors.ConflictError(`Failed to update status to '${status}' for taskId ${taskId}`);
3798
+ throw new errors.ConflictError(
3799
+ `Failed to update status to '${status}' for taskId ${taskId}`
3800
+ );
3269
3801
  }
3270
3802
  await tx("task_events").insert({
3271
3803
  task_id: taskId,
@@ -3305,7 +3837,9 @@ class DatabaseTaskStore {
3305
3837
  createdAt: parseSqlDateToIsoString(event.created_at)
3306
3838
  };
3307
3839
  } catch (error) {
3308
- throw new Error(`Failed to parse event body from event taskId=${taskId} id=${event.id}, ${error}`);
3840
+ throw new Error(
3841
+ `Failed to parse event body from event taskId=${taskId} id=${event.id}, ${error}`
3842
+ );
3309
3843
  }
3310
3844
  });
3311
3845
  return { events };
@@ -3366,7 +3900,10 @@ class TaskManager {
3366
3900
  this.startTimeout();
3367
3901
  } catch (error) {
3368
3902
  this.isDone = true;
3369
- this.logger.error(`Heartbeat for task ${this.task.taskId} failed`, error);
3903
+ this.logger.error(
3904
+ `Heartbeat for task ${this.task.taskId} failed`,
3905
+ error
3906
+ );
3370
3907
  }
3371
3908
  }, 1e3);
3372
3909
  }
@@ -3387,7 +3924,9 @@ class StorageTaskBroker {
3387
3924
  }
3388
3925
  async list(options) {
3389
3926
  if (!this.storage.list) {
3390
- throw new Error("TaskStore does not implement the list method. Please implement the list method to be able to list tasks");
3927
+ throw new Error(
3928
+ "TaskStore does not implement the list method. Please implement the list method to be able to list tasks"
3929
+ );
3391
3930
  }
3392
3931
  return await this.storage.list({ createdBy: options == null ? void 0 : options.createdBy });
3393
3932
  }
@@ -3395,12 +3934,16 @@ class StorageTaskBroker {
3395
3934
  for (; ; ) {
3396
3935
  const pendingTask = await this.storage.claimTask();
3397
3936
  if (pendingTask) {
3398
- return TaskManager.create({
3399
- taskId: pendingTask.id,
3400
- spec: pendingTask.spec,
3401
- secrets: pendingTask.secrets,
3402
- createdBy: pendingTask.createdBy
3403
- }, this.storage, this.logger);
3937
+ return TaskManager.create(
3938
+ {
3939
+ taskId: pendingTask.id,
3940
+ spec: pendingTask.spec,
3941
+ secrets: pendingTask.secrets,
3942
+ createdBy: pendingTask.createdBy
3943
+ },
3944
+ this.storage,
3945
+ this.logger
3946
+ );
3404
3947
  }
3405
3948
  await this.waitForDispatch();
3406
3949
  }
@@ -3438,19 +3981,21 @@ class StorageTaskBroker {
3438
3981
  }
3439
3982
  async vacuumTasks(options) {
3440
3983
  const { tasks } = await this.storage.listStaleTasks(options);
3441
- await Promise.all(tasks.map(async (task) => {
3442
- try {
3443
- await this.storage.completeTask({
3444
- taskId: task.taskId,
3445
- status: "failed",
3446
- eventBody: {
3447
- message: "The task was cancelled because the task worker lost connection to the task broker"
3448
- }
3449
- });
3450
- } catch (error) {
3451
- this.logger.warn(`Failed to cancel task '${task.taskId}', ${error}`);
3452
- }
3453
- }));
3984
+ await Promise.all(
3985
+ tasks.map(async (task) => {
3986
+ try {
3987
+ await this.storage.completeTask({
3988
+ taskId: task.taskId,
3989
+ status: "failed",
3990
+ eventBody: {
3991
+ message: "The task was cancelled because the task worker lost connection to the task broker"
3992
+ }
3993
+ });
3994
+ } catch (error) {
3995
+ this.logger.warn(`Failed to cancel task '${task.taskId}', ${error}`);
3996
+ }
3997
+ })
3998
+ );
3454
3999
  }
3455
4000
  waitForDispatch() {
3456
4001
  return this.deferredDispatch.promise;
@@ -3471,10 +4016,12 @@ function generateExampleOutput(schema) {
3471
4016
  return examples[0];
3472
4017
  }
3473
4018
  if (schema.type === "object") {
3474
- return Object.fromEntries(Object.entries((_a = schema.properties) != null ? _a : {}).map(([key, value]) => [
3475
- key,
3476
- generateExampleOutput(value)
3477
- ]));
4019
+ return Object.fromEntries(
4020
+ Object.entries((_a = schema.properties) != null ? _a : {}).map(([key, value]) => [
4021
+ key,
4022
+ generateExampleOutput(value)
4023
+ ])
4024
+ );
3478
4025
  } else if (schema.type === "array") {
3479
4026
  const [firstSchema] = (_b = [schema.items]) == null ? void 0 : _b.flat();
3480
4027
  if (firstSchema) {
@@ -3501,7 +4048,11 @@ const createStepLogger = ({
3501
4048
  const metadata = { stepId: step.id };
3502
4049
  const taskLogger = winston__namespace.createLogger({
3503
4050
  level: process.env.LOG_LEVEL || "info",
3504
- format: winston__namespace.format.combine(winston__namespace.format.colorize(), winston__namespace.format.timestamp(), winston__namespace.format.simple()),
4051
+ format: winston__namespace.format.combine(
4052
+ winston__namespace.format.colorize(),
4053
+ winston__namespace.format.timestamp(),
4054
+ winston__namespace.format.simple()
4055
+ ),
3505
4056
  defaultMeta: {}
3506
4057
  });
3507
4058
  const streamLogger = new stream.PassThrough();
@@ -3521,13 +4072,17 @@ class NunjucksWorkflowRunner {
3521
4072
  isSingleTemplateString(input) {
3522
4073
  var _a, _b;
3523
4074
  const { parser, nodes } = nunjucks__default["default"];
3524
- const parsed = parser.parse(input, {}, {
3525
- autoescape: false,
3526
- tags: {
3527
- variableStart: "${{",
3528
- variableEnd: "}}"
4075
+ const parsed = parser.parse(
4076
+ input,
4077
+ {},
4078
+ {
4079
+ autoescape: false,
4080
+ tags: {
4081
+ variableStart: "${{",
4082
+ variableEnd: "}}"
4083
+ }
3529
4084
  }
3530
- });
4085
+ );
3531
4086
  return parsed.children.length === 1 && !(((_b = (_a = parsed.children[0]) == null ? void 0 : _a.children) == null ? void 0 : _b[0]) instanceof nodes.TemplateData);
3532
4087
  }
3533
4088
  render(input, context, renderTemplate) {
@@ -3536,7 +4091,10 @@ class NunjucksWorkflowRunner {
3536
4091
  if (typeof value === "string") {
3537
4092
  try {
3538
4093
  if (this.isSingleTemplateString(value)) {
3539
- const wrappedDumped = value.replace(/\${{(.+)}}/g, "${{ ( $1 ) | dump }}");
4094
+ const wrappedDumped = value.replace(
4095
+ /\${{(.+)}}/g,
4096
+ "${{ ( $1 ) | dump }}"
4097
+ );
3540
4098
  const templated2 = renderTemplate(wrappedDumped, context);
3541
4099
  if (templated2 === "") {
3542
4100
  return void 0;
@@ -3544,7 +4102,9 @@ class NunjucksWorkflowRunner {
3544
4102
  return JSON.parse(templated2);
3545
4103
  }
3546
4104
  } catch (ex) {
3547
- this.options.logger.error(`Failed to parse template string: ${value} with error ${ex.message}`);
4105
+ this.options.logger.error(
4106
+ `Failed to parse template string: ${value} with error ${ex.message}`
4107
+ );
3548
4108
  }
3549
4109
  const templated = renderTemplate(value, context);
3550
4110
  if (templated === "") {
@@ -3561,9 +4121,14 @@ class NunjucksWorkflowRunner {
3561
4121
  async execute(task) {
3562
4122
  var _a, _b, _c, _d, _e;
3563
4123
  if (!isValidTaskSpec(task.spec)) {
3564
- throw new errors.InputError("Wrong template version executed with the workflow engine");
4124
+ throw new errors.InputError(
4125
+ "Wrong template version executed with the workflow engine"
4126
+ );
3565
4127
  }
3566
- const workspacePath = path__default["default"].join(this.options.workingDirectory, await task.getWorkspaceName());
4128
+ const workspacePath = path__default["default"].join(
4129
+ this.options.workingDirectory,
4130
+ await task.getWorkspaceName()
4131
+ );
3567
4132
  const { integrations } = this.options;
3568
4133
  const renderTemplate = await SecureTemplater.loadRenderer({
3569
4134
  parseRepoUrl(url) {
@@ -3573,7 +4138,9 @@ class NunjucksWorkflowRunner {
3573
4138
  });
3574
4139
  try {
3575
4140
  await fs__default["default"].ensureDir(workspacePath);
3576
- await task.emitLog(`Starting up task with ${task.spec.steps.length} steps`);
4141
+ await task.emitLog(
4142
+ `Starting up task with ${task.spec.steps.length} steps`
4143
+ );
3577
4144
  const context = {
3578
4145
  parameters: task.spec.parameters,
3579
4146
  steps: {},
@@ -3582,9 +4149,16 @@ class NunjucksWorkflowRunner {
3582
4149
  for (const step of task.spec.steps) {
3583
4150
  try {
3584
4151
  if (step.if) {
3585
- const ifResult = await this.render(step.if, context, renderTemplate);
4152
+ const ifResult = await this.render(
4153
+ step.if,
4154
+ context,
4155
+ renderTemplate
4156
+ );
3586
4157
  if (!isTruthy(ifResult)) {
3587
- await task.emitLog(`Skipping step ${step.id} because it's if condition was false`, { stepId: step.id, status: "skipped" });
4158
+ await task.emitLog(
4159
+ `Skipping step ${step.id} because it's if condition was false`,
4160
+ { stepId: step.id, status: "skipped" }
4161
+ );
3588
4162
  continue;
3589
4163
  }
3590
4164
  }
@@ -3595,10 +4169,13 @@ class NunjucksWorkflowRunner {
3595
4169
  const action = this.options.actionRegistry.get(step.action);
3596
4170
  const { taskLogger, streamLogger } = createStepLogger({ task, step });
3597
4171
  if (task.isDryRun && !action.supportsDryRun) {
3598
- task.emitLog(`Skipping because ${action.id} does not support dry-run`, {
3599
- stepId: step.id,
3600
- status: "skipped"
3601
- });
4172
+ task.emitLog(
4173
+ `Skipping because ${action.id} does not support dry-run`,
4174
+ {
4175
+ stepId: step.id,
4176
+ status: "skipped"
4177
+ }
4178
+ );
3602
4179
  const outputSchema = (_a = action.schema) == null ? void 0 : _a.output;
3603
4180
  if (outputSchema) {
3604
4181
  context.steps[step.id] = {
@@ -3609,12 +4186,21 @@ class NunjucksWorkflowRunner {
3609
4186
  }
3610
4187
  continue;
3611
4188
  }
3612
- const input = (_c = step.input && this.render(step.input, { ...context, secrets: (_b = task.secrets) != null ? _b : {} }, renderTemplate)) != null ? _c : {};
4189
+ const input = (_c = step.input && this.render(
4190
+ step.input,
4191
+ { ...context, secrets: (_b = task.secrets) != null ? _b : {} },
4192
+ renderTemplate
4193
+ )) != null ? _c : {};
3613
4194
  if ((_d = action.schema) == null ? void 0 : _d.input) {
3614
- const validateResult = jsonschema.validate(input, action.schema.input);
4195
+ const validateResult = jsonschema.validate(
4196
+ input,
4197
+ action.schema.input
4198
+ );
3615
4199
  if (!validateResult.valid) {
3616
4200
  const errors$1 = validateResult.errors.join(", ");
3617
- throw new errors.InputError(`Invalid input passed to action ${action.id}, ${errors$1}`);
4201
+ throw new errors.InputError(
4202
+ `Invalid input passed to action ${action.id}, ${errors$1}`
4203
+ );
3618
4204
  }
3619
4205
  }
3620
4206
  const tmpDirs = new Array();
@@ -3626,7 +4212,9 @@ class NunjucksWorkflowRunner {
3626
4212
  logStream: streamLogger,
3627
4213
  workspacePath,
3628
4214
  createTemporaryDirectory: async () => {
3629
- const tmpDir = await fs__default["default"].mkdtemp(`${workspacePath}_step-${step.id}-`);
4215
+ const tmpDir = await fs__default["default"].mkdtemp(
4216
+ `${workspacePath}_step-${step.id}-`
4217
+ );
3630
4218
  tmpDirs.push(tmpDir);
3631
4219
  return tmpDir;
3632
4220
  },
@@ -3697,9 +4285,13 @@ class TaskWorker {
3697
4285
  async runOneTask(task) {
3698
4286
  try {
3699
4287
  if (task.spec.apiVersion !== "scaffolder.backstage.io/v1beta3") {
3700
- throw new Error(`Unsupported Template apiVersion ${task.spec.apiVersion}`);
4288
+ throw new Error(
4289
+ `Unsupported Template apiVersion ${task.spec.apiVersion}`
4290
+ );
3701
4291
  }
3702
- const { output } = await this.options.runners.workflowRunner.execute(task);
4292
+ const { output } = await this.options.runners.workflowRunner.execute(
4293
+ task
4294
+ );
3703
4295
  await task.complete("completed", { output });
3704
4296
  } catch (error) {
3705
4297
  errors.assertError(error);
@@ -3746,7 +4338,10 @@ function createDryRunner(options) {
3746
4338
  });
3747
4339
  const dryRunId = uuid.v4();
3748
4340
  const log = new Array();
3749
- const contentsPath = backendCommon.resolveSafeChildPath(options.workingDirectory, `dry-run-content-${dryRunId}`);
4341
+ const contentsPath = backendCommon.resolveSafeChildPath(
4342
+ options.workingDirectory,
4343
+ `dry-run-content-${dryRunId}`
4344
+ );
3750
4345
  try {
3751
4346
  await deserializeDirectoryContents(contentsPath, input.directoryContents);
3752
4347
  const result = await workflowRunner.execute({
@@ -3762,7 +4357,9 @@ function createDryRunner(options) {
3762
4357
  ],
3763
4358
  templateInfo: {
3764
4359
  entityRef: "template:default/dry-run",
3765
- baseUrl: url.pathToFileURL(backendCommon.resolveSafeChildPath(contentsPath, "template.yaml")).toString()
4360
+ baseUrl: url.pathToFileURL(
4361
+ backendCommon.resolveSafeChildPath(contentsPath, "template.yaml")
4362
+ ).toString()
3766
4363
  }
3767
4364
  },
3768
4365
  secrets: input.secrets,
@@ -3809,7 +4406,9 @@ async function getWorkingDirectory(config, logger) {
3809
4406
  logger.info(`using working directory: ${workingDirectory}`);
3810
4407
  } catch (err) {
3811
4408
  errors.assertError(err);
3812
- logger.error(`working directory ${workingDirectory} ${err.code === "ENOENT" ? "does not exist" : "is not writable"}`);
4409
+ logger.error(
4410
+ `working directory ${workingDirectory} ${err.code === "ENOENT" ? "does not exist" : "is not writable"}`
4411
+ );
3813
4412
  throw err;
3814
4413
  }
3815
4414
  return workingDirectory;
@@ -3838,7 +4437,9 @@ async function findTemplate(options) {
3838
4437
  }
3839
4438
  const template = await catalogApi.getEntityByRef(entityRef, { token });
3840
4439
  if (!template) {
3841
- throw new errors.NotFoundError(`Template ${catalogModel.stringifyEntityRef(entityRef)} not found`);
4440
+ throw new errors.NotFoundError(
4441
+ `Template ${catalogModel.stringifyEntityRef(entityRef)} not found`
4442
+ );
3842
4443
  }
3843
4444
  return template;
3844
4445
  }
@@ -3900,31 +4501,38 @@ async function createRouter(options) {
3900
4501
  workingDirectory,
3901
4502
  additionalTemplateFilters
3902
4503
  });
3903
- router.get("/v2/templates/:namespace/:kind/:name/parameter-schema", async (req, res) => {
3904
- var _a, _b;
3905
- const { namespace, kind, name } = req.params;
3906
- const { token } = parseBearerToken(req.headers.authorization);
3907
- const template = await findTemplate({
3908
- catalogApi: catalogClient,
3909
- entityRef: { kind, namespace, name },
3910
- token
3911
- });
3912
- if (isSupportedTemplate(template)) {
3913
- const parameters = [(_a = template.spec.parameters) != null ? _a : []].flat();
3914
- res.json({
3915
- title: (_b = template.metadata.title) != null ? _b : template.metadata.name,
3916
- steps: parameters.map((schema) => {
3917
- var _a2;
3918
- return {
3919
- title: (_a2 = schema.title) != null ? _a2 : "Fill in template parameters",
3920
- schema
3921
- };
3922
- })
4504
+ router.get(
4505
+ "/v2/templates/:namespace/:kind/:name/parameter-schema",
4506
+ async (req, res) => {
4507
+ var _a, _b;
4508
+ const { namespace, kind, name } = req.params;
4509
+ const { token } = parseBearerToken(req.headers.authorization);
4510
+ const template = await findTemplate({
4511
+ catalogApi: catalogClient,
4512
+ entityRef: { kind, namespace, name },
4513
+ token
3923
4514
  });
3924
- } else {
3925
- throw new errors.InputError(`Unsupported apiVersion field in schema entity, ${template.apiVersion}`);
4515
+ if (isSupportedTemplate(template)) {
4516
+ const parameters = [(_a = template.spec.parameters) != null ? _a : []].flat();
4517
+ res.json({
4518
+ title: (_b = template.metadata.title) != null ? _b : template.metadata.name,
4519
+ description: template.metadata.description,
4520
+ steps: parameters.map((schema) => {
4521
+ var _a2;
4522
+ return {
4523
+ title: (_a2 = schema.title) != null ? _a2 : "Please enter the following information",
4524
+ description: schema.description,
4525
+ schema
4526
+ };
4527
+ })
4528
+ });
4529
+ } else {
4530
+ throw new errors.InputError(
4531
+ `Unsupported apiVersion field in schema entity, ${template.apiVersion}`
4532
+ );
4533
+ }
3926
4534
  }
3927
- }).get("/v2/actions", async (_req, res) => {
4535
+ ).get("/v2/actions", async (_req, res) => {
3928
4536
  const actionsList = actionRegistry.list().map((action) => {
3929
4537
  return {
3930
4538
  id: action.id,
@@ -3939,7 +4547,9 @@ async function createRouter(options) {
3939
4547
  const { kind, namespace, name } = catalogModel.parseEntityRef(templateRef, {
3940
4548
  defaultKind: "template"
3941
4549
  });
3942
- const { token, entityRef: userEntityRef } = parseBearerToken(req.headers.authorization);
4550
+ const { token, entityRef: userEntityRef } = parseBearerToken(
4551
+ req.headers.authorization
4552
+ );
3943
4553
  const userEntity = userEntityRef ? await catalogClient.getEntityByRef(userEntityRef, { token }) : void 0;
3944
4554
  let auditLog = `Scaffolding task for ${templateRef}`;
3945
4555
  if (userEntityRef) {
@@ -3953,7 +4563,9 @@ async function createRouter(options) {
3953
4563
  token
3954
4564
  });
3955
4565
  if (!isSupportedTemplate(template)) {
3956
- throw new errors.InputError(`Unsupported apiVersion field in schema entity, ${template.apiVersion}`);
4566
+ throw new errors.InputError(
4567
+ `Unsupported apiVersion field in schema entity, ${template.apiVersion}`
4568
+ );
3957
4569
  }
3958
4570
  for (const parameters of [(_a = template.spec.parameters) != null ? _a : []].flat()) {
3959
4571
  const result2 = jsonschema.validate(values, parameters);
@@ -4003,7 +4615,9 @@ async function createRouter(options) {
4003
4615
  throw new errors.InputError("createdBy query parameter must be a string");
4004
4616
  }
4005
4617
  if (!taskBroker.list) {
4006
- throw new Error("TaskBroker does not support listing tasks, please implement the list method on the TaskBroker.");
4618
+ throw new Error(
4619
+ "TaskBroker does not support listing tasks, please implement the list method on the TaskBroker."
4620
+ );
4007
4621
  }
4008
4622
  const tasks = await taskBroker.list({
4009
4623
  createdBy: userEntityRef
@@ -4028,23 +4642,30 @@ async function createRouter(options) {
4028
4642
  });
4029
4643
  const subscription = taskBroker.event$({ taskId, after }).subscribe({
4030
4644
  error: (error) => {
4031
- logger.error(`Received error from event stream when observing taskId '${taskId}', ${error}`);
4645
+ logger.error(
4646
+ `Received error from event stream when observing taskId '${taskId}', ${error}`
4647
+ );
4648
+ res.end();
4032
4649
  },
4033
4650
  next: ({ events }) => {
4034
4651
  var _a;
4035
4652
  let shouldUnsubscribe = false;
4036
4653
  for (const event of events) {
4037
- res.write(`event: ${event.type}
4654
+ res.write(
4655
+ `event: ${event.type}
4038
4656
  data: ${JSON.stringify(event)}
4039
4657
 
4040
- `);
4658
+ `
4659
+ );
4041
4660
  if (event.type === "completion") {
4042
4661
  shouldUnsubscribe = true;
4043
4662
  }
4044
4663
  }
4045
4664
  (_a = res.flush) == null ? void 0 : _a.call(res);
4046
- if (shouldUnsubscribe)
4665
+ if (shouldUnsubscribe) {
4047
4666
  subscription.unsubscribe();
4667
+ res.end();
4668
+ }
4048
4669
  }
4049
4670
  });
4050
4671
  req.on("close", () => {
@@ -4059,7 +4680,9 @@ data: ${JSON.stringify(event)}
4059
4680
  }, 3e4);
4060
4681
  const subscription = taskBroker.event$({ taskId, after }).subscribe({
4061
4682
  error: (error) => {
4062
- logger.error(`Received error from event stream when observing taskId '${taskId}', ${error}`);
4683
+ logger.error(
4684
+ `Received error from event stream when observing taskId '${taskId}', ${error}`
4685
+ );
4063
4686
  },
4064
4687
  next: ({ events }) => {
4065
4688
  clearTimeout(timeout);
@@ -4077,7 +4700,9 @@ data: ${JSON.stringify(event)}
4077
4700
  template: zod.z.unknown(),
4078
4701
  values: zod.z.record(zod.z.unknown()),
4079
4702
  secrets: zod.z.record(zod.z.string()).optional(),
4080
- directoryContents: zod.z.array(zod.z.object({ path: zod.z.string(), base64Content: zod.z.string() }))
4703
+ directoryContents: zod.z.array(
4704
+ zod.z.object({ path: zod.z.string(), base64Content: zod.z.string() })
4705
+ )
4081
4706
  });
4082
4707
  const body = await bodySchema.parseAsync(req.body).catch((e) => {
4083
4708
  throw new errors.InputError(`Malformed request: ${e}`);
@@ -4144,7 +4769,9 @@ function parseBearerToken(header) {
4144
4769
  throw new TypeError("Expected Bearer with JWT");
4145
4770
  }
4146
4771
  const [_header, rawPayload, _signature] = token.split(".");
4147
- const payload = JSON.parse(Buffer.from(rawPayload, "base64").toString());
4772
+ const payload = JSON.parse(
4773
+ Buffer.from(rawPayload, "base64").toString()
4774
+ );
4148
4775
  if (typeof payload !== "object" || payload === null || Array.isArray(payload)) {
4149
4776
  throw new TypeError("Malformed JWT payload");
4150
4777
  }
@@ -4183,24 +4810,28 @@ class ScaffolderEntitiesProcessor {
4183
4810
  defaultKind: "Group",
4184
4811
  defaultNamespace: selfRef.namespace
4185
4812
  });
4186
- emit(pluginCatalogBackend.processingResult.relation({
4187
- source: selfRef,
4188
- type: catalogModel.RELATION_OWNED_BY,
4189
- target: {
4190
- kind: targetRef.kind,
4191
- namespace: targetRef.namespace,
4192
- name: targetRef.name
4193
- }
4194
- }));
4195
- emit(pluginCatalogBackend.processingResult.relation({
4196
- source: {
4197
- kind: targetRef.kind,
4198
- namespace: targetRef.namespace,
4199
- name: targetRef.name
4200
- },
4201
- type: catalogModel.RELATION_OWNER_OF,
4202
- target: selfRef
4203
- }));
4813
+ emit(
4814
+ pluginCatalogBackend.processingResult.relation({
4815
+ source: selfRef,
4816
+ type: catalogModel.RELATION_OWNED_BY,
4817
+ target: {
4818
+ kind: targetRef.kind,
4819
+ namespace: targetRef.namespace,
4820
+ name: targetRef.name
4821
+ }
4822
+ })
4823
+ );
4824
+ emit(
4825
+ pluginCatalogBackend.processingResult.relation({
4826
+ source: {
4827
+ kind: targetRef.kind,
4828
+ namespace: targetRef.namespace,
4829
+ name: targetRef.name
4830
+ },
4831
+ type: catalogModel.RELATION_OWNER_OF,
4832
+ target: selfRef
4833
+ })
4834
+ );
4204
4835
  }
4205
4836
  }
4206
4837
  return entity;
@@ -4216,7 +4847,9 @@ const scaffolderCatalogModule = backendPluginApi.createBackendModule({
4216
4847
  catalogProcessingExtensionPoint: pluginCatalogNode.catalogProcessingExtentionPoint
4217
4848
  },
4218
4849
  async init({ catalogProcessingExtensionPoint }) {
4219
- catalogProcessingExtensionPoint.addProcessor(new ScaffolderEntitiesProcessor());
4850
+ catalogProcessingExtensionPoint.addProcessor(
4851
+ new ScaffolderEntitiesProcessor()
4852
+ );
4220
4853
  }
4221
4854
  });
4222
4855
  }
@@ -4246,6 +4879,7 @@ exports.createPublishBitbucketCloudAction = createPublishBitbucketCloudAction;
4246
4879
  exports.createPublishBitbucketServerAction = createPublishBitbucketServerAction;
4247
4880
  exports.createPublishFileAction = createPublishFileAction;
4248
4881
  exports.createPublishGerritAction = createPublishGerritAction;
4882
+ exports.createPublishGerritReviewAction = createPublishGerritReviewAction;
4249
4883
  exports.createPublishGithubAction = createPublishGithubAction;
4250
4884
  exports.createPublishGithubPullRequestAction = createPublishGithubPullRequestAction;
4251
4885
  exports.createPublishGitlabAction = createPublishGitlabAction;