@backstage/plugin-scaffolder-backend 1.4.0-next.3 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,58 @@
1
1
  # @backstage/plugin-scaffolder-backend
2
2
 
3
+ ## 1.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - e1a08d872c: Added optional assignee parameter for Gitlab Merge Request action
8
+ - dab9bcf2e7: Add `protectEnforceAdmins` as an option to GitHub publish actions
9
+ - 4baf8a4ece: Update GitLab Merge Request Action to allow source branch to be deleted
10
+ - 91c1d12123: Export experimental `scaffolderCatalogExtension` for the new backend system. This export is not considered stable and should not be used in production.
11
+ - d10ccc2ed1: Introduced audit log message when a new scaffolder task is created
12
+ - 2db07887cb: Added two new scaffolder actions: `github:repo:create` and `github:repo:push`
13
+
14
+ ### Patch Changes
15
+
16
+ - ff316b86d8: Add `copyWithoutTemplating` to the fetch template action input. `copyWithoutTemplating` also accepts an array of glob patterns. Contents of matched files or directories are copied without being processed, but paths are subject to rendering.
17
+
18
+ Deprecate `copyWithoutRender` in favor of `copyWithoutTemplating`.
19
+
20
+ - 801d606909: Improve error messaging when passing in malformed auth
21
+ - 089d846962: Fix issues with optional directories and files
22
+ - ea6dcb84a4: Don't resolve symlinks, treat them as binary files and copy them as-is
23
+ - af02f54483: new setUserAsOwner flag for publish:gitlab action
24
+
25
+ The field default is `false`. When true it will use the token configured in the gitlab integration for the matching host, to try and set the user logged in via `repoUrlPicker` `requestUserCredentials` OAuth flow as owner of the repository created in GitLab.
26
+
27
+ - a70869e775: Updated dependency `msw` to `^0.43.0`.
28
+ - 4e9a90e307: Updated dependency `luxon` to `^3.0.0`.
29
+ - 72622d9143: Updated dependency `yaml` to `^2.0.0`.
30
+ - 8006d0f9bf: Updated dependency `msw` to `^0.44.0`.
31
+ - 679b32172e: Updated dependency `knex` to `^2.0.0`.
32
+ - 511f49ee43: Updated dependency `octokit` to `^2.0.0`.
33
+ - 735853353b: Updated dependency `@octokit/webhooks` to `^10.0.0`.
34
+ - e2d7b76f43: Upgrade git-url-parse to 12.0.0.
35
+
36
+ Motivation for upgrade is transitively upgrading parse-url which is vulnerable
37
+ to several CVEs detected by Snyk.
38
+
39
+ - SNYK-JS-PARSEURL-2935944
40
+ - SNYK-JS-PARSEURL-2935947
41
+ - SNYK-JS-PARSEURL-2936249
42
+
43
+ - 945a27fa6a: Add sourcePath option to publish:gerrit action
44
+ - 1764296a68: Allow to create Gerrit project using default owner
45
+ - Updated dependencies
46
+ - @backstage/backend-plugin-api@0.1.0
47
+ - @backstage/plugin-catalog-backend@1.3.0
48
+ - @backstage/backend-common@0.14.1
49
+ - @backstage/catalog-model@1.1.0
50
+ - @backstage/plugin-catalog-node@1.0.0
51
+ - @backstage/integration@1.2.2
52
+ - @backstage/catalog-client@1.0.4
53
+ - @backstage/errors@1.1.0
54
+ - @backstage/plugin-scaffolder-common@1.1.2
55
+
3
56
  ## 1.4.0-next.3
4
57
 
5
58
  ### Minor Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/plugin-scaffolder-backend",
3
- "version": "1.4.0-next.3",
3
+ "version": "1.4.0",
4
4
  "main": "../dist/index.cjs.js",
5
5
  "types": "../dist/index.alpha.d.ts"
6
6
  }
@@ -161,7 +161,11 @@ url: string;
161
161
  targetPath?: string | undefined;
162
162
  values: any;
163
163
  templateFileExtension?: string | boolean | undefined;
164
+ /**
165
+ * @deprecated This field is deprecated in favor of copyWithoutTemplating.
166
+ */
164
167
  copyWithoutRender?: string[] | undefined;
168
+ copyWithoutTemplating?: string[] | undefined;
165
169
  cookiecutterCompat?: boolean | undefined;
166
170
  }>;
167
171
 
@@ -299,6 +303,7 @@ repoUrl: string;
299
303
  description?: string | undefined;
300
304
  defaultBranch?: string | undefined;
301
305
  protectDefaultBranch?: boolean | undefined;
306
+ protectEnforceAdmins?: boolean | undefined;
302
307
  gitCommitMessage?: string | undefined;
303
308
  gitAuthorName?: string | undefined;
304
309
  gitAuthorEmail?: string | undefined;
@@ -433,6 +438,7 @@ defaultBranch?: string | undefined;
433
438
  gitCommitMessage?: string | undefined;
434
439
  gitAuthorName?: string | undefined;
435
440
  gitAuthorEmail?: string | undefined;
441
+ sourcePath?: string | undefined;
436
442
  }>;
437
443
 
438
444
  /**
@@ -451,6 +457,7 @@ description?: string | undefined;
451
457
  access?: string | undefined;
452
458
  defaultBranch?: string | undefined;
453
459
  protectDefaultBranch?: boolean | undefined;
460
+ protectEnforceAdmins?: boolean | undefined;
454
461
  deleteBranchOnMerge?: boolean | undefined;
455
462
  gitCommitMessage?: string | undefined;
456
463
  gitAuthorName?: string | undefined;
@@ -530,6 +537,7 @@ token?: string | undefined;
530
537
  /** @deprecated Use projectPath instead */
531
538
  projectid?: string | undefined;
532
539
  removeSourceBranch?: boolean | undefined;
540
+ assignee?: string | undefined;
533
541
  }>;
534
542
 
535
543
  /**
@@ -161,7 +161,11 @@ url: string;
161
161
  targetPath?: string | undefined;
162
162
  values: any;
163
163
  templateFileExtension?: string | boolean | undefined;
164
+ /**
165
+ * @deprecated This field is deprecated in favor of copyWithoutTemplating.
166
+ */
164
167
  copyWithoutRender?: string[] | undefined;
168
+ copyWithoutTemplating?: string[] | undefined;
165
169
  cookiecutterCompat?: boolean | undefined;
166
170
  }>;
167
171
 
@@ -299,6 +303,7 @@ repoUrl: string;
299
303
  description?: string | undefined;
300
304
  defaultBranch?: string | undefined;
301
305
  protectDefaultBranch?: boolean | undefined;
306
+ protectEnforceAdmins?: boolean | undefined;
302
307
  gitCommitMessage?: string | undefined;
303
308
  gitAuthorName?: string | undefined;
304
309
  gitAuthorEmail?: string | undefined;
@@ -433,6 +438,7 @@ defaultBranch?: string | undefined;
433
438
  gitCommitMessage?: string | undefined;
434
439
  gitAuthorName?: string | undefined;
435
440
  gitAuthorEmail?: string | undefined;
441
+ sourcePath?: string | undefined;
436
442
  }>;
437
443
 
438
444
  /**
@@ -451,6 +457,7 @@ description?: string | undefined;
451
457
  access?: string | undefined;
452
458
  defaultBranch?: string | undefined;
453
459
  protectDefaultBranch?: boolean | undefined;
460
+ protectEnforceAdmins?: boolean | undefined;
454
461
  deleteBranchOnMerge?: boolean | undefined;
455
462
  gitCommitMessage?: string | undefined;
456
463
  gitAuthorName?: string | undefined;
@@ -530,6 +537,7 @@ token?: string | undefined;
530
537
  /** @deprecated Use projectPath instead */
531
538
  projectid?: string | undefined;
532
539
  removeSourceBranch?: boolean | undefined;
540
+ assignee?: string | undefined;
533
541
  }>;
534
542
 
535
543
  /**
package/dist/index.cjs.js CHANGED
@@ -473,13 +473,21 @@ function createFetchTemplateAction(options) {
473
473
  type: "object"
474
474
  },
475
475
  copyWithoutRender: {
476
- title: "Copy Without Render",
476
+ title: "[Deprecated] Copy Without Render",
477
477
  description: "An array of glob patterns. Any files or directories which match are copied without being processed as templates.",
478
478
  type: "array",
479
479
  items: {
480
480
  type: "string"
481
481
  }
482
482
  },
483
+ copyWithoutTemplating: {
484
+ title: "Copy Without Templating",
485
+ description: "An array of glob patterns. Contents of matched files or directories are copied without being processed, but paths are subject to rendering.",
486
+ type: "array",
487
+ items: {
488
+ type: "string"
489
+ }
490
+ },
483
491
  cookiecutterCompat: {
484
492
  title: "Cookiecutter compatibility mode",
485
493
  description: "Enable features to maximise compatibility with templates built for fetch:cookiecutter",
@@ -501,11 +509,24 @@ function createFetchTemplateAction(options) {
501
509
  const templateDir = backendCommon.resolveSafeChildPath(workDir, "template");
502
510
  const targetPath = (_a = ctx.input.targetPath) != null ? _a : "./";
503
511
  const outputDir = backendCommon.resolveSafeChildPath(ctx.workspacePath, targetPath);
504
- if (ctx.input.copyWithoutRender && !Array.isArray(ctx.input.copyWithoutRender)) {
505
- throw new errors.InputError("Fetch action input copyWithoutRender must be an Array");
512
+ 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");
514
+ }
515
+ let copyOnlyPatterns;
516
+ let renderFilename;
517
+ if (ctx.input.copyWithoutRender) {
518
+ ctx.logger.warn("[Deprecated] Please use copyWithoutTemplating instead.");
519
+ copyOnlyPatterns = ctx.input.copyWithoutRender;
520
+ renderFilename = false;
521
+ } else {
522
+ copyOnlyPatterns = ctx.input.copyWithoutTemplating;
523
+ renderFilename = true;
524
+ }
525
+ if (copyOnlyPatterns && !Array.isArray(copyOnlyPatterns)) {
526
+ throw new errors.InputError("Fetch action input copyWithoutRender/copyWithoutTemplating must be an Array");
506
527
  }
507
- if (ctx.input.templateFileExtension && (ctx.input.copyWithoutRender || ctx.input.cookiecutterCompat)) {
508
- throw new errors.InputError("Fetch action input extension incompatible with copyWithoutRender and cookiecutterCompat");
528
+ if (ctx.input.templateFileExtension && (copyOnlyPatterns || ctx.input.cookiecutterCompat)) {
529
+ throw new errors.InputError("Fetch action input extension incompatible with copyWithoutRender/copyWithoutTemplating and cookiecutterCompat");
509
530
  }
510
531
  let extension = false;
511
532
  if (ctx.input.templateFileExtension) {
@@ -529,7 +550,7 @@ function createFetchTemplateAction(options) {
529
550
  markDirectories: true,
530
551
  followSymbolicLinks: false
531
552
  });
532
- const nonTemplatedEntries = new Set((await Promise.all((ctx.input.copyWithoutRender || []).map((pattern) => globby__default["default"](pattern, {
553
+ const nonTemplatedEntries = new Set((await Promise.all((copyOnlyPatterns || []).map((pattern) => globby__default["default"](pattern, {
533
554
  cwd: templateDir,
534
555
  dot: true,
535
556
  onlyFiles: false,
@@ -546,23 +567,27 @@ function createFetchTemplateAction(options) {
546
567
  additionalTemplateFilters
547
568
  });
548
569
  for (const location of allEntriesInTemplate) {
549
- let renderFilename;
550
570
  let renderContents;
551
571
  let localOutputPath = location;
552
572
  if (extension) {
553
- renderFilename = true;
554
573
  renderContents = path.extname(localOutputPath) === extension;
555
574
  if (renderContents) {
556
575
  localOutputPath = localOutputPath.slice(0, -extension.length);
557
576
  }
577
+ localOutputPath = renderTemplate(localOutputPath, context);
558
578
  } else {
559
- renderFilename = renderContents = !nonTemplatedEntries.has(location);
579
+ renderContents = !nonTemplatedEntries.has(location);
580
+ if (renderFilename) {
581
+ localOutputPath = renderTemplate(localOutputPath, context);
582
+ } else {
583
+ localOutputPath = renderContents ? renderTemplate(localOutputPath, context) : localOutputPath;
584
+ }
560
585
  }
561
- if (renderFilename) {
562
- localOutputPath = renderTemplate(localOutputPath, context);
586
+ if (containsSkippedContent(localOutputPath)) {
587
+ continue;
563
588
  }
564
589
  const outputPath = backendCommon.resolveSafeChildPath(outputDir, localOutputPath);
565
- if (outputDir === outputPath) {
590
+ if (fs__default["default"].existsSync(outputPath)) {
566
591
  continue;
567
592
  }
568
593
  if (!renderContents && !extension) {
@@ -589,6 +614,9 @@ function createFetchTemplateAction(options) {
589
614
  }
590
615
  });
591
616
  }
617
+ function containsSkippedContent(localOutputPath) {
618
+ return localOutputPath === "" || path__default["default"].isAbsolute(localOutputPath) || localOutputPath.includes(`${path__default["default"].sep}${path__default["default"].sep}`);
619
+ }
592
620
 
593
621
  const createFilesystemDeleteAction = () => {
594
622
  return createTemplateAction({
@@ -729,7 +757,7 @@ const parseRepoUrl = (repoUrl, integrations) => {
729
757
  throw new errors.InputError(`Invalid repo URL passed to publisher: ${repoUrl}, missing project`);
730
758
  }
731
759
  } else {
732
- if (!owner) {
760
+ if (!owner && type !== "gerrit") {
733
761
  throw new errors.InputError(`Invalid repo URL passed to publisher: ${repoUrl}, missing owner`);
734
762
  }
735
763
  }
@@ -813,7 +841,8 @@ const enableBranchProtectionOnDefaultRepoBranch = async ({
813
841
  logger,
814
842
  requireCodeOwnerReviews,
815
843
  requiredStatusCheckContexts = [],
816
- defaultBranch = "master"
844
+ defaultBranch = "master",
845
+ enforceAdmins = true
817
846
  }) => {
818
847
  const tryOnce = async () => {
819
848
  try {
@@ -829,7 +858,7 @@ const enableBranchProtectionOnDefaultRepoBranch = async ({
829
858
  contexts: requiredStatusCheckContexts
830
859
  },
831
860
  restrictions: null,
832
- enforce_admins: true,
861
+ enforce_admins: enforceAdmins,
833
862
  required_pull_request_reviews: {
834
863
  required_approving_review_count: 1,
835
864
  require_code_owner_reviews: requireCodeOwnerReviews
@@ -981,7 +1010,7 @@ async function createGithubRepoWithCollaboratorsAndTopics(client, repo, owner, r
981
1010
  }
982
1011
  return newRepo;
983
1012
  }
984
- async function initRepoPushAndProtect(remoteUrl, password, workspacePath, sourcePath, defaultBranch, protectDefaultBranch, owner, client, repo, requireCodeOwnerReviews, requiredStatusCheckContexts, config, logger, gitCommitMessage, gitAuthorName, gitAuthorEmail) {
1013
+ async function initRepoPushAndProtect(remoteUrl, password, workspacePath, sourcePath, defaultBranch, protectDefaultBranch, protectEnforceAdmins, owner, client, repo, requireCodeOwnerReviews, requiredStatusCheckContexts, config, logger, gitCommitMessage, gitAuthorName, gitAuthorEmail) {
985
1014
  const gitAuthorInfo = {
986
1015
  name: gitAuthorName ? gitAuthorName : config.getOptionalString("scaffolder.defaultAuthor.name"),
987
1016
  email: gitAuthorEmail ? gitAuthorEmail : config.getOptionalString("scaffolder.defaultAuthor.email")
@@ -1008,7 +1037,8 @@ async function initRepoPushAndProtect(remoteUrl, password, workspacePath, source
1008
1037
  logger,
1009
1038
  defaultBranch,
1010
1039
  requireCodeOwnerReviews,
1011
- requiredStatusCheckContexts
1040
+ requiredStatusCheckContexts,
1041
+ enforceAdmins: protectEnforceAdmins
1012
1042
  });
1013
1043
  } catch (e) {
1014
1044
  errors.assertError(e);
@@ -1267,6 +1297,11 @@ const protectDefaultBranch = {
1267
1297
  type: "boolean",
1268
1298
  description: `Protect the default branch after creating the repository. The default value is 'true'`
1269
1299
  };
1300
+ const protectEnforceAdmins = {
1301
+ title: "Enforce Admins On Protected Branches",
1302
+ type: "boolean",
1303
+ description: `Enforce admins to adhere to default branch protection. The default value is 'true'`
1304
+ };
1270
1305
  const gitCommitMessage = {
1271
1306
  title: "Git Commit Message",
1272
1307
  type: "string",
@@ -1366,6 +1401,7 @@ function createGithubRepoPushAction(options) {
1366
1401
  requiredStatusCheckContexts: requiredStatusCheckContexts,
1367
1402
  defaultBranch: defaultBranch,
1368
1403
  protectDefaultBranch: protectDefaultBranch,
1404
+ protectEnforceAdmins: protectEnforceAdmins,
1369
1405
  gitCommitMessage: gitCommitMessage,
1370
1406
  gitAuthorName: gitAuthorName,
1371
1407
  gitAuthorEmail: gitAuthorEmail,
@@ -1386,6 +1422,7 @@ function createGithubRepoPushAction(options) {
1386
1422
  repoUrl,
1387
1423
  defaultBranch = "master",
1388
1424
  protectDefaultBranch = true,
1425
+ protectEnforceAdmins = true,
1389
1426
  gitCommitMessage = "initial commit",
1390
1427
  gitAuthorName,
1391
1428
  gitAuthorEmail,
@@ -1407,7 +1444,7 @@ function createGithubRepoPushAction(options) {
1407
1444
  const targetRepo = await client.rest.repos.get({ owner, repo });
1408
1445
  const remoteUrl = targetRepo.data.clone_url;
1409
1446
  const repoContentsUrl = `${targetRepo.data.html_url}/blob/${defaultBranch}`;
1410
- await initRepoPushAndProtect(remoteUrl, octokitOptions.auth, ctx.workspacePath, ctx.input.sourcePath, defaultBranch, protectDefaultBranch, owner, client, repo, requireCodeOwnerReviews, requiredStatusCheckContexts, config, ctx.logger, gitCommitMessage, gitAuthorName, gitAuthorEmail);
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);
1411
1448
  ctx.output("remoteUrl", remoteUrl);
1412
1449
  ctx.output("repoContentsUrl", repoContentsUrl);
1413
1450
  }
@@ -2282,7 +2319,7 @@ const createGerritProject = async (config, options) => {
2282
2319
  body: JSON.stringify({
2283
2320
  parent,
2284
2321
  description,
2285
- owners: [owner],
2322
+ owners: owner ? [owner] : [],
2286
2323
  create_empty_commit: false
2287
2324
  }),
2288
2325
  headers: {
@@ -2339,6 +2376,11 @@ function createPublishGerritAction(options) {
2339
2376
  title: "Default Author Email",
2340
2377
  type: "string",
2341
2378
  description: `Sets the default author email for the commit.`
2379
+ },
2380
+ sourcePath: {
2381
+ title: "Source Path",
2382
+ type: "string",
2383
+ description: `Path within the workspace that will be used as the repository root. If omitted, the entire workspace will be published as the repository.`
2342
2384
  }
2343
2385
  }
2344
2386
  },
@@ -2363,16 +2405,14 @@ function createPublishGerritAction(options) {
2363
2405
  defaultBranch = "master",
2364
2406
  gitAuthorName,
2365
2407
  gitAuthorEmail,
2366
- gitCommitMessage = "initial commit"
2408
+ gitCommitMessage = "initial commit",
2409
+ sourcePath
2367
2410
  } = ctx.input;
2368
2411
  const { repo, host, owner, workspace } = parseRepoUrl(repoUrl, integrations);
2369
2412
  const integrationConfig = integrations.gerrit.byHost(host);
2370
2413
  if (!integrationConfig) {
2371
2414
  throw new errors.InputError(`No matching integration configuration for host ${host}, please check your integrations config`);
2372
2415
  }
2373
- if (!owner) {
2374
- throw new errors.InputError(`Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing owner`);
2375
- }
2376
2416
  if (!workspace) {
2377
2417
  throw new errors.InputError(`Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing workspace`);
2378
2418
  }
@@ -2392,7 +2432,7 @@ function createPublishGerritAction(options) {
2392
2432
  };
2393
2433
  const remoteUrl = `${integrationConfig.config.cloneUrl}/a/${repo}`;
2394
2434
  await initRepoAndPush({
2395
- dir: getRepoSourceDirectory(ctx.workspacePath, void 0),
2435
+ dir: getRepoSourceDirectory(ctx.workspacePath, sourcePath),
2396
2436
  remoteUrl,
2397
2437
  auth,
2398
2438
  defaultBranch,
@@ -2425,6 +2465,7 @@ function createPublishGithubAction(options) {
2425
2465
  repoVisibility: repoVisibility,
2426
2466
  defaultBranch: defaultBranch,
2427
2467
  protectDefaultBranch: protectDefaultBranch,
2468
+ protectEnforceAdmins: protectEnforceAdmins,
2428
2469
  deleteBranchOnMerge: deleteBranchOnMerge,
2429
2470
  gitCommitMessage: gitCommitMessage,
2430
2471
  gitAuthorName: gitAuthorName,
@@ -2456,6 +2497,7 @@ function createPublishGithubAction(options) {
2456
2497
  repoVisibility = "private",
2457
2498
  defaultBranch = "master",
2458
2499
  protectDefaultBranch = true,
2500
+ protectEnforceAdmins = true,
2459
2501
  deleteBranchOnMerge = false,
2460
2502
  gitCommitMessage = "initial commit",
2461
2503
  gitAuthorName,
@@ -2481,7 +2523,7 @@ function createPublishGithubAction(options) {
2481
2523
  const newRepo = await createGithubRepoWithCollaboratorsAndTopics(client, repo, owner, repoVisibility, description, deleteBranchOnMerge, allowMergeCommit, allowSquashMerge, allowRebaseMerge, access, collaborators, topics, ctx.logger);
2482
2524
  const remoteUrl = newRepo.clone_url;
2483
2525
  const repoContentsUrl = `${newRepo.html_url}/blob/${defaultBranch}`;
2484
- await initRepoPushAndProtect(remoteUrl, octokitOptions.auth, ctx.workspacePath, ctx.input.sourcePath, defaultBranch, protectDefaultBranch, owner, client, repo, requireCodeOwnerReviews, requiredStatusCheckContexts, config, ctx.logger, gitCommitMessage, gitAuthorName, gitAuthorEmail);
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);
2485
2527
  ctx.output("remoteUrl", remoteUrl);
2486
2528
  ctx.output("repoContentsUrl", repoContentsUrl);
2487
2529
  }
@@ -2862,6 +2904,11 @@ const createPublishGitlabMergeRequestAction = (options) => {
2862
2904
  title: "Delete source branch",
2863
2905
  type: "boolean",
2864
2906
  description: "Option to delete source branch once the MR has been merged. Default: false"
2907
+ },
2908
+ assignee: {
2909
+ title: "Merge Request Assignee",
2910
+ type: "string",
2911
+ description: "User this merge request will be assigned to"
2865
2912
  }
2866
2913
  }
2867
2914
  },
@@ -2908,6 +2955,16 @@ const createPublishGitlabMergeRequestAction = (options) => {
2908
2955
  host: integrationConfig.config.baseUrl,
2909
2956
  [tokenType]: token
2910
2957
  });
2958
+ const assignee = ctx.input.assignee;
2959
+ let assigneeId = void 0;
2960
+ if (assignee !== void 0) {
2961
+ try {
2962
+ const assigneeUser = await api.Users.username(assignee);
2963
+ assigneeId = assigneeUser[0].id;
2964
+ } catch (e) {
2965
+ ctx.logger.warn(`Failed to find gitlab user id for ${assignee}: ${e}. Proceeding with MR creation without an assignee.`);
2966
+ }
2967
+ }
2911
2968
  const targetPath = backendCommon.resolveSafeChildPath(ctx.workspacePath, ctx.input.targetPath);
2912
2969
  const fileContents = await serializeDirectoryContents(targetPath, {
2913
2970
  gitignore: true
@@ -2934,7 +2991,8 @@ const createPublishGitlabMergeRequestAction = (options) => {
2934
2991
  try {
2935
2992
  const mergeRequestUrl = await api.MergeRequests.create(projectPath, destinationBranch, String(defaultBranch), ctx.input.title, {
2936
2993
  description: ctx.input.description,
2937
- removeSourceBranch: ctx.input.removeSourceBranch ? ctx.input.removeSourceBranch : false
2994
+ removeSourceBranch: ctx.input.removeSourceBranch ? ctx.input.removeSourceBranch : false,
2995
+ assigneeId
2938
2996
  }).then((mergeRequest) => {
2939
2997
  return mergeRequest.web_url;
2940
2998
  });
@@ -3883,6 +3941,11 @@ async function createRouter(options) {
3883
3941
  });
3884
3942
  const { token, entityRef: userEntityRef } = parseBearerToken(req.headers.authorization);
3885
3943
  const userEntity = userEntityRef ? await catalogClient.getEntityByRef(userEntityRef, { token }) : void 0;
3944
+ let auditLog = `Scaffolding task for ${templateRef}`;
3945
+ if (userEntityRef) {
3946
+ auditLog += ` created by ${userEntityRef}`;
3947
+ }
3948
+ logger.info(auditLog);
3886
3949
  const values = req.body.values;
3887
3950
  const template = await findTemplate({
3888
3951
  catalogApi: catalogClient,