@backstage/plugin-scaffolder-backend 1.1.0 → 1.2.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/dist/index.cjs.js CHANGED
@@ -734,6 +734,7 @@ const enableBranchProtectionOnDefaultRepoBranch = async ({
734
734
  owner,
735
735
  logger,
736
736
  requireCodeOwnerReviews,
737
+ requiredStatusCheckContexts = [],
737
738
  defaultBranch = "master"
738
739
  }) => {
739
740
  const tryOnce = async () => {
@@ -745,7 +746,10 @@ const enableBranchProtectionOnDefaultRepoBranch = async ({
745
746
  owner,
746
747
  repo: repoName,
747
748
  branch: defaultBranch,
748
- required_status_checks: { strict: true, contexts: [] },
749
+ required_status_checks: {
750
+ strict: true,
751
+ contexts: requiredStatusCheckContexts
752
+ },
749
753
  restrictions: null,
750
754
  enforce_admins: true,
751
755
  required_pull_request_reviews: {
@@ -850,6 +854,21 @@ function createPublishAzureAction(options) {
850
854
  type: "string",
851
855
  description: `Sets the default branch on the repository. The default value is 'master'`
852
856
  },
857
+ gitCommitMessage: {
858
+ title: "Git Commit Message",
859
+ type: "string",
860
+ description: `Sets the commit message on the repository. The default value is 'initial commit'`
861
+ },
862
+ gitAuthorName: {
863
+ title: "Default Author Name",
864
+ type: "string",
865
+ description: `Sets the default author name for the commit. The default value is 'Scaffolder'`
866
+ },
867
+ gitAuthorEmail: {
868
+ title: "Default Author Email",
869
+ type: "string",
870
+ description: `Sets the default author email for the commit.`
871
+ },
853
872
  sourcePath: {
854
873
  title: "Source Path",
855
874
  description: "Path within the workspace that will be used as the repository root. If omitted, the entire workspace will be published as the repository.",
@@ -878,7 +897,13 @@ function createPublishAzureAction(options) {
878
897
  },
879
898
  async handler(ctx) {
880
899
  var _a;
881
- const { repoUrl, defaultBranch = "master" } = ctx.input;
900
+ const {
901
+ repoUrl,
902
+ defaultBranch = "master",
903
+ gitCommitMessage = "initial commit",
904
+ gitAuthorName,
905
+ gitAuthorEmail
906
+ } = ctx.input;
882
907
  const { owner, repo, host, organization } = parseRepoUrl(repoUrl, integrations);
883
908
  if (!organization) {
884
909
  throw new errors.InputError(`Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing organization`);
@@ -906,8 +931,8 @@ function createPublishAzureAction(options) {
906
931
  }
907
932
  const repoContentsUrl = remoteUrl;
908
933
  const gitAuthorInfo = {
909
- name: config.getOptionalString("scaffolder.defaultAuthor.name"),
910
- email: config.getOptionalString("scaffolder.defaultAuthor.email")
934
+ name: gitAuthorName ? gitAuthorName : config.getOptionalString("scaffolder.defaultAuthor.name"),
935
+ email: gitAuthorEmail ? gitAuthorEmail : config.getOptionalString("scaffolder.defaultAuthor.email")
911
936
  };
912
937
  await initRepoAndPush({
913
938
  dir: getRepoSourceDirectory(ctx.workspacePath, ctx.input.sourcePath),
@@ -918,7 +943,7 @@ function createPublishAzureAction(options) {
918
943
  password: token
919
944
  },
920
945
  logger: ctx.logger,
921
- commitMessage: config.getOptionalString("scaffolder.defaultCommitMessage"),
946
+ commitMessage: gitCommitMessage ? gitCommitMessage : config.getOptionalString("scaffolder.defaultCommitMessage"),
922
947
  gitAuthorInfo
923
948
  });
924
949
  ctx.output("remoteUrl", remoteUrl);
@@ -1010,7 +1035,7 @@ const createBitbucketServerRepository = async (opts) => {
1010
1035
  const repoContentsUrl = `${r.links.self[0].href}`;
1011
1036
  return { remoteUrl, repoContentsUrl };
1012
1037
  };
1013
- const getAuthorizationHeader = (config) => {
1038
+ const getAuthorizationHeader$2 = (config) => {
1014
1039
  if (config.username && config.appPassword) {
1015
1040
  const buffer = Buffer.from(`${config.username}:${config.appPassword}`, "utf8");
1016
1041
  return `Basic ${buffer.toString("base64")}`;
@@ -1020,7 +1045,7 @@ const getAuthorizationHeader = (config) => {
1020
1045
  }
1021
1046
  throw new Error(`Authorization has not been provided for Bitbucket. Please add either username + appPassword or token to the Integrations config`);
1022
1047
  };
1023
- const performEnableLFS = async (opts) => {
1048
+ const performEnableLFS$1 = async (opts) => {
1024
1049
  const { authorization, host, project, repo } = opts;
1025
1050
  const options = {
1026
1051
  method: "PUT",
@@ -1074,6 +1099,21 @@ function createPublishBitbucketAction(options) {
1074
1099
  title: "Authentication Token",
1075
1100
  type: "string",
1076
1101
  description: "The token to use for authorization to BitBucket"
1102
+ },
1103
+ gitCommitMessage: {
1104
+ title: "Git Commit Message",
1105
+ type: "string",
1106
+ description: `Sets the commit message on the repository. The default value is 'initial commit'`
1107
+ },
1108
+ gitAuthorName: {
1109
+ title: "Default Author Name",
1110
+ type: "string",
1111
+ description: `Sets the default author name for the commit. The default value is 'Scaffolder'`
1112
+ },
1113
+ gitAuthorEmail: {
1114
+ title: "Default Author Email",
1115
+ type: "string",
1116
+ description: `Sets the default author email for the commit.`
1077
1117
  }
1078
1118
  }
1079
1119
  },
@@ -1093,12 +1133,16 @@ function createPublishBitbucketAction(options) {
1093
1133
  },
1094
1134
  async handler(ctx) {
1095
1135
  var _a;
1136
+ ctx.logger.warn(`[Deprecated] Please migrate the use of action "publish:bitbucket" to "publish:bitbucketCloud" or "publish:bitbucketServer".`);
1096
1137
  const {
1097
1138
  repoUrl,
1098
1139
  description,
1099
1140
  defaultBranch = "master",
1100
1141
  repoVisibility = "private",
1101
- enableLFS = false
1142
+ enableLFS = false,
1143
+ gitCommitMessage = "initial commit",
1144
+ gitAuthorName,
1145
+ gitAuthorEmail
1102
1146
  } = ctx.input;
1103
1147
  const { workspace, project, repo, host } = parseRepoUrl(repoUrl, integrations);
1104
1148
  if (host === "bitbucket.org") {
@@ -1113,7 +1157,7 @@ function createPublishBitbucketAction(options) {
1113
1157
  if (!integrationConfig) {
1114
1158
  throw new errors.InputError(`No matching integration configuration for host ${host}, please check your integrations config`);
1115
1159
  }
1116
- const authorization = getAuthorizationHeader(ctx.input.token ? {
1160
+ const authorization = getAuthorizationHeader$2(ctx.input.token ? {
1117
1161
  host: integrationConfig.config.host,
1118
1162
  apiBaseUrl: integrationConfig.config.apiBaseUrl,
1119
1163
  token: ctx.input.token
@@ -1131,8 +1175,8 @@ function createPublishBitbucketAction(options) {
1131
1175
  apiBaseUrl
1132
1176
  });
1133
1177
  const gitAuthorInfo = {
1134
- name: config.getOptionalString("scaffolder.defaultAuthor.name"),
1135
- email: config.getOptionalString("scaffolder.defaultAuthor.email")
1178
+ name: gitAuthorName ? gitAuthorName : config.getOptionalString("scaffolder.defaultAuthor.name"),
1179
+ email: gitAuthorEmail ? gitAuthorEmail : config.getOptionalString("scaffolder.defaultAuthor.email")
1136
1180
  };
1137
1181
  let auth;
1138
1182
  if (ctx.input.token) {
@@ -1152,10 +1196,352 @@ function createPublishBitbucketAction(options) {
1152
1196
  auth,
1153
1197
  defaultBranch,
1154
1198
  logger: ctx.logger,
1155
- commitMessage: config.getOptionalString("scaffolder.defaultCommitMessage"),
1199
+ commitMessage: gitCommitMessage ? gitCommitMessage : config.getOptionalString("scaffolder.defaultCommitMessage"),
1156
1200
  gitAuthorInfo
1157
1201
  });
1158
1202
  if (enableLFS && host !== "bitbucket.org") {
1203
+ await performEnableLFS$1({ authorization, host, project, repo });
1204
+ }
1205
+ ctx.output("remoteUrl", remoteUrl);
1206
+ ctx.output("repoContentsUrl", repoContentsUrl);
1207
+ }
1208
+ });
1209
+ }
1210
+
1211
+ const createRepository$1 = async (opts) => {
1212
+ const {
1213
+ workspace,
1214
+ project,
1215
+ repo,
1216
+ description,
1217
+ repoVisibility,
1218
+ mainBranch,
1219
+ authorization,
1220
+ apiBaseUrl
1221
+ } = opts;
1222
+ const options = {
1223
+ method: "POST",
1224
+ body: JSON.stringify({
1225
+ scm: "git",
1226
+ description,
1227
+ is_private: repoVisibility === "private",
1228
+ project: { key: project }
1229
+ }),
1230
+ headers: {
1231
+ Authorization: authorization,
1232
+ "Content-Type": "application/json"
1233
+ }
1234
+ };
1235
+ let response;
1236
+ try {
1237
+ response = await fetch__default["default"](`${apiBaseUrl}/repositories/${workspace}/${repo}`, options);
1238
+ } catch (e) {
1239
+ throw new Error(`Unable to create repository, ${e}`);
1240
+ }
1241
+ if (response.status !== 200) {
1242
+ throw new Error(`Unable to create repository, ${response.status} ${response.statusText}, ${await response.text()}`);
1243
+ }
1244
+ const r = await response.json();
1245
+ let remoteUrl = "";
1246
+ for (const link of r.links.clone) {
1247
+ if (link.name === "https") {
1248
+ remoteUrl = link.href;
1249
+ }
1250
+ }
1251
+ const repoContentsUrl = `${r.links.html.href}/src/${mainBranch}`;
1252
+ return { remoteUrl, repoContentsUrl };
1253
+ };
1254
+ const getAuthorizationHeader$1 = (config) => {
1255
+ if (config.username && config.appPassword) {
1256
+ const buffer = Buffer.from(`${config.username}:${config.appPassword}`, "utf8");
1257
+ return `Basic ${buffer.toString("base64")}`;
1258
+ }
1259
+ if (config.token) {
1260
+ return `Bearer ${config.token}`;
1261
+ }
1262
+ 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`);
1263
+ };
1264
+ function createPublishBitbucketCloudAction(options) {
1265
+ const { integrations, config } = options;
1266
+ return createTemplateAction({
1267
+ id: "publish:bitbucketCloud",
1268
+ description: "Initializes a git repository of the content in the workspace, and publishes it to Bitbucket Cloud.",
1269
+ schema: {
1270
+ input: {
1271
+ type: "object",
1272
+ required: ["repoUrl"],
1273
+ properties: {
1274
+ repoUrl: {
1275
+ title: "Repository Location",
1276
+ type: "string"
1277
+ },
1278
+ description: {
1279
+ title: "Repository Description",
1280
+ type: "string"
1281
+ },
1282
+ repoVisibility: {
1283
+ title: "Repository Visibility",
1284
+ type: "string",
1285
+ enum: ["private", "public"]
1286
+ },
1287
+ defaultBranch: {
1288
+ title: "Default Branch",
1289
+ type: "string",
1290
+ description: `Sets the default branch on the repository. The default value is 'master'`
1291
+ },
1292
+ sourcePath: {
1293
+ title: "Source Path",
1294
+ description: "Path within the workspace that will be used as the repository root. If omitted, the entire workspace will be published as the repository.",
1295
+ type: "string"
1296
+ },
1297
+ token: {
1298
+ title: "Authentication Token",
1299
+ type: "string",
1300
+ description: "The token to use for authorization to BitBucket Cloud"
1301
+ }
1302
+ }
1303
+ },
1304
+ output: {
1305
+ type: "object",
1306
+ properties: {
1307
+ remoteUrl: {
1308
+ title: "A URL to the repository with the provider",
1309
+ type: "string"
1310
+ },
1311
+ repoContentsUrl: {
1312
+ title: "A URL to the root of the repository",
1313
+ type: "string"
1314
+ }
1315
+ }
1316
+ }
1317
+ },
1318
+ async handler(ctx) {
1319
+ const {
1320
+ repoUrl,
1321
+ description,
1322
+ defaultBranch = "master",
1323
+ repoVisibility = "private"
1324
+ } = ctx.input;
1325
+ const { workspace, project, repo, host } = parseRepoUrl(repoUrl, integrations);
1326
+ if (!workspace) {
1327
+ throw new errors.InputError(`Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing workspace`);
1328
+ }
1329
+ if (!project) {
1330
+ throw new errors.InputError(`Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing project`);
1331
+ }
1332
+ const integrationConfig = integrations.bitbucketCloud.byHost(host);
1333
+ if (!integrationConfig) {
1334
+ throw new errors.InputError(`No matching integration configuration for host ${host}, please check your integrations config`);
1335
+ }
1336
+ const authorization = getAuthorizationHeader$1(ctx.input.token ? { token: ctx.input.token } : integrationConfig.config);
1337
+ const apiBaseUrl = integrationConfig.config.apiBaseUrl;
1338
+ const { remoteUrl, repoContentsUrl } = await createRepository$1({
1339
+ authorization,
1340
+ workspace: workspace || "",
1341
+ project,
1342
+ repo,
1343
+ repoVisibility,
1344
+ mainBranch: defaultBranch,
1345
+ description,
1346
+ apiBaseUrl
1347
+ });
1348
+ const gitAuthorInfo = {
1349
+ name: config.getOptionalString("scaffolder.defaultAuthor.name"),
1350
+ email: config.getOptionalString("scaffolder.defaultAuthor.email")
1351
+ };
1352
+ let auth;
1353
+ if (ctx.input.token) {
1354
+ auth = {
1355
+ username: "x-token-auth",
1356
+ password: ctx.input.token
1357
+ };
1358
+ } else {
1359
+ if (!integrationConfig.config.username || !integrationConfig.config.appPassword) {
1360
+ throw new Error("Credentials for Bitbucket Cloud integration required for this action.");
1361
+ }
1362
+ auth = {
1363
+ username: integrationConfig.config.username,
1364
+ password: integrationConfig.config.appPassword
1365
+ };
1366
+ }
1367
+ await initRepoAndPush({
1368
+ dir: getRepoSourceDirectory(ctx.workspacePath, ctx.input.sourcePath),
1369
+ remoteUrl,
1370
+ auth,
1371
+ defaultBranch,
1372
+ logger: ctx.logger,
1373
+ commitMessage: config.getOptionalString("scaffolder.defaultCommitMessage"),
1374
+ gitAuthorInfo
1375
+ });
1376
+ ctx.output("remoteUrl", remoteUrl);
1377
+ ctx.output("repoContentsUrl", repoContentsUrl);
1378
+ }
1379
+ });
1380
+ }
1381
+
1382
+ const createRepository = async (opts) => {
1383
+ const {
1384
+ project,
1385
+ repo,
1386
+ description,
1387
+ authorization,
1388
+ repoVisibility,
1389
+ apiBaseUrl
1390
+ } = opts;
1391
+ let response;
1392
+ const options = {
1393
+ method: "POST",
1394
+ body: JSON.stringify({
1395
+ name: repo,
1396
+ description,
1397
+ public: repoVisibility === "public"
1398
+ }),
1399
+ headers: {
1400
+ Authorization: authorization,
1401
+ "Content-Type": "application/json"
1402
+ }
1403
+ };
1404
+ try {
1405
+ response = await fetch__default["default"](`${apiBaseUrl}/projects/${project}/repos`, options);
1406
+ } catch (e) {
1407
+ throw new Error(`Unable to create repository, ${e}`);
1408
+ }
1409
+ if (response.status !== 201) {
1410
+ throw new Error(`Unable to create repository, ${response.status} ${response.statusText}, ${await response.text()}`);
1411
+ }
1412
+ const r = await response.json();
1413
+ let remoteUrl = "";
1414
+ for (const link of r.links.clone) {
1415
+ if (link.name === "http") {
1416
+ remoteUrl = link.href;
1417
+ }
1418
+ }
1419
+ const repoContentsUrl = `${r.links.self[0].href}`;
1420
+ return { remoteUrl, repoContentsUrl };
1421
+ };
1422
+ const getAuthorizationHeader = (config) => {
1423
+ return `Bearer ${config.token}`;
1424
+ };
1425
+ const performEnableLFS = async (opts) => {
1426
+ const { authorization, host, project, repo } = opts;
1427
+ const options = {
1428
+ method: "PUT",
1429
+ headers: {
1430
+ Authorization: authorization
1431
+ }
1432
+ };
1433
+ const { ok, status, statusText } = await fetch__default["default"](`https://${host}/rest/git-lfs/admin/projects/${project}/repos/${repo}/enabled`, options);
1434
+ if (!ok)
1435
+ throw new Error(`Failed to enable LFS in the repository, ${status}: ${statusText}`);
1436
+ };
1437
+ function createPublishBitbucketServerAction(options) {
1438
+ const { integrations, config } = options;
1439
+ return createTemplateAction({
1440
+ id: "publish:bitbucketServer",
1441
+ description: "Initializes a git repository of the content in the workspace, and publishes it to Bitbucket Server.",
1442
+ schema: {
1443
+ input: {
1444
+ type: "object",
1445
+ required: ["repoUrl"],
1446
+ properties: {
1447
+ repoUrl: {
1448
+ title: "Repository Location",
1449
+ type: "string"
1450
+ },
1451
+ description: {
1452
+ title: "Repository Description",
1453
+ type: "string"
1454
+ },
1455
+ repoVisibility: {
1456
+ title: "Repository Visibility",
1457
+ type: "string",
1458
+ enum: ["private", "public"]
1459
+ },
1460
+ defaultBranch: {
1461
+ title: "Default Branch",
1462
+ type: "string",
1463
+ description: `Sets the default branch on the repository. The default value is 'master'`
1464
+ },
1465
+ sourcePath: {
1466
+ title: "Source Path",
1467
+ description: "Path within the workspace that will be used as the repository root. If omitted, the entire workspace will be published as the repository.",
1468
+ type: "string"
1469
+ },
1470
+ enableLFS: {
1471
+ title: "Enable LFS?",
1472
+ description: "Enable LFS for the repository.",
1473
+ type: "boolean"
1474
+ },
1475
+ token: {
1476
+ title: "Authentication Token",
1477
+ type: "string",
1478
+ description: "The token to use for authorization to BitBucket Server"
1479
+ }
1480
+ }
1481
+ },
1482
+ output: {
1483
+ type: "object",
1484
+ properties: {
1485
+ remoteUrl: {
1486
+ title: "A URL to the repository with the provider",
1487
+ type: "string"
1488
+ },
1489
+ repoContentsUrl: {
1490
+ title: "A URL to the root of the repository",
1491
+ type: "string"
1492
+ }
1493
+ }
1494
+ }
1495
+ },
1496
+ async handler(ctx) {
1497
+ var _a;
1498
+ const {
1499
+ repoUrl,
1500
+ description,
1501
+ defaultBranch = "master",
1502
+ repoVisibility = "private",
1503
+ enableLFS = false
1504
+ } = ctx.input;
1505
+ const { project, repo, host } = parseRepoUrl(repoUrl, integrations);
1506
+ if (!project) {
1507
+ throw new errors.InputError(`Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing project`);
1508
+ }
1509
+ const integrationConfig = integrations.bitbucketServer.byHost(host);
1510
+ if (!integrationConfig) {
1511
+ throw new errors.InputError(`No matching integration configuration for host ${host}, please check your integrations config`);
1512
+ }
1513
+ const token = (_a = ctx.input.token) != null ? _a : integrationConfig.config.token;
1514
+ if (!token) {
1515
+ 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`);
1516
+ }
1517
+ const authorization = getAuthorizationHeader({ token });
1518
+ const apiBaseUrl = integrationConfig.config.apiBaseUrl;
1519
+ const { remoteUrl, repoContentsUrl } = await createRepository({
1520
+ authorization,
1521
+ project,
1522
+ repo,
1523
+ repoVisibility,
1524
+ description,
1525
+ apiBaseUrl
1526
+ });
1527
+ const gitAuthorInfo = {
1528
+ name: config.getOptionalString("scaffolder.defaultAuthor.name"),
1529
+ email: config.getOptionalString("scaffolder.defaultAuthor.email")
1530
+ };
1531
+ const auth = {
1532
+ username: "x-token-auth",
1533
+ password: token
1534
+ };
1535
+ await initRepoAndPush({
1536
+ dir: getRepoSourceDirectory(ctx.workspacePath, ctx.input.sourcePath),
1537
+ remoteUrl,
1538
+ auth,
1539
+ defaultBranch,
1540
+ logger: ctx.logger,
1541
+ commitMessage: config.getOptionalString("scaffolder.defaultCommitMessage"),
1542
+ gitAuthorInfo
1543
+ });
1544
+ if (enableLFS) {
1159
1545
  await performEnableLFS({ authorization, host, project, repo });
1160
1546
  }
1161
1547
  ctx.output("remoteUrl", remoteUrl);
@@ -1258,6 +1644,14 @@ function createPublishGithubAction(options) {
1258
1644
  description: "Require an approved review in PR including files with a designated Code Owner",
1259
1645
  type: "boolean"
1260
1646
  },
1647
+ requiredStatusCheckContexts: {
1648
+ title: "Required Status Check Contexts",
1649
+ description: "The list of status checks to require in order to merge into this branch",
1650
+ type: "array",
1651
+ items: {
1652
+ type: "string"
1653
+ }
1654
+ },
1261
1655
  repoVisibility: {
1262
1656
  title: "Repository Visibility",
1263
1657
  type: "string",
@@ -1273,6 +1667,21 @@ function createPublishGithubAction(options) {
1273
1667
  type: "boolean",
1274
1668
  description: `Delete the branch after merging the PR. The default value is 'false'`
1275
1669
  },
1670
+ gitCommitMessage: {
1671
+ title: "Git Commit Message",
1672
+ type: "string",
1673
+ description: `Sets the commit message on the repository. The default value is 'initial commit'`
1674
+ },
1675
+ gitAuthorName: {
1676
+ title: "Default Author Name",
1677
+ type: "string",
1678
+ description: `Sets the default author name for the commit. The default value is 'Scaffolder'`
1679
+ },
1680
+ gitAuthorEmail: {
1681
+ title: "Default Author Email",
1682
+ type: "string",
1683
+ description: `Sets the default author email for the commit.`
1684
+ },
1276
1685
  allowMergeCommit: {
1277
1686
  title: "Allow Merge Commits",
1278
1687
  type: "boolean",
@@ -1347,9 +1756,13 @@ function createPublishGithubAction(options) {
1347
1756
  description,
1348
1757
  access,
1349
1758
  requireCodeOwnerReviews = false,
1759
+ requiredStatusCheckContexts = [],
1350
1760
  repoVisibility = "private",
1351
1761
  defaultBranch = "master",
1352
1762
  deleteBranchOnMerge = false,
1763
+ gitCommitMessage = "initial commit",
1764
+ gitAuthorName,
1765
+ gitAuthorEmail,
1353
1766
  allowMergeCommit = true,
1354
1767
  allowSquashMerge = true,
1355
1768
  allowRebaseMerge = true,
@@ -1442,8 +1855,8 @@ function createPublishGithubAction(options) {
1442
1855
  const remoteUrl = newRepo.clone_url;
1443
1856
  const repoContentsUrl = `${newRepo.html_url}/blob/${defaultBranch}`;
1444
1857
  const gitAuthorInfo = {
1445
- name: config.getOptionalString("scaffolder.defaultAuthor.name"),
1446
- email: config.getOptionalString("scaffolder.defaultAuthor.email")
1858
+ name: gitAuthorName ? gitAuthorName : config.getOptionalString("scaffolder.defaultAuthor.name"),
1859
+ email: gitAuthorEmail ? gitAuthorEmail : config.getOptionalString("scaffolder.defaultAuthor.email")
1447
1860
  };
1448
1861
  await initRepoAndPush({
1449
1862
  dir: getRepoSourceDirectory(ctx.workspacePath, ctx.input.sourcePath),
@@ -1454,7 +1867,7 @@ function createPublishGithubAction(options) {
1454
1867
  password: octokitOptions.auth
1455
1868
  },
1456
1869
  logger: ctx.logger,
1457
- commitMessage: config.getOptionalString("scaffolder.defaultCommitMessage"),
1870
+ commitMessage: gitCommitMessage ? gitCommitMessage : config.getOptionalString("scaffolder.defaultCommitMessage"),
1458
1871
  gitAuthorInfo
1459
1872
  });
1460
1873
  try {
@@ -1464,7 +1877,8 @@ function createPublishGithubAction(options) {
1464
1877
  repoName: newRepo.name,
1465
1878
  logger: ctx.logger,
1466
1879
  defaultBranch,
1467
- requireCodeOwnerReviews
1880
+ requireCodeOwnerReviews,
1881
+ requiredStatusCheckContexts
1468
1882
  });
1469
1883
  } catch (e) {
1470
1884
  errors.assertError(e);
@@ -2172,6 +2586,14 @@ const createBuiltinActions = (options) => {
2172
2586
  integrations,
2173
2587
  config
2174
2588
  }),
2589
+ createPublishBitbucketCloudAction({
2590
+ integrations,
2591
+ config
2592
+ }),
2593
+ createPublishBitbucketServerAction({
2594
+ integrations,
2595
+ config
2596
+ }),
2175
2597
  createPublishAzureAction({
2176
2598
  integrations,
2177
2599
  config
@@ -2231,6 +2653,7 @@ class DatabaseTaskStore {
2231
2653
  this.db = options.database;
2232
2654
  }
2233
2655
  async getTask(taskId) {
2656
+ var _a;
2234
2657
  const [result] = await this.db("tasks").where({ id: taskId }).select();
2235
2658
  if (!result) {
2236
2659
  throw new errors.NotFoundError(`No task with id '${taskId}' found`);
@@ -2244,6 +2667,7 @@ class DatabaseTaskStore {
2244
2667
  status: result.status,
2245
2668
  lastHeartbeatAt: result.last_heartbeat_at,
2246
2669
  createdAt: result.created_at,
2670
+ createdBy: (_a = result.created_by) != null ? _a : void 0,
2247
2671
  secrets
2248
2672
  };
2249
2673
  } catch (error) {
@@ -2251,17 +2675,20 @@ class DatabaseTaskStore {
2251
2675
  }
2252
2676
  }
2253
2677
  async createTask(options) {
2678
+ var _a;
2254
2679
  const taskId = uuid.v4();
2255
2680
  await this.db("tasks").insert({
2256
2681
  id: taskId,
2257
2682
  spec: JSON.stringify(options.spec),
2258
2683
  secrets: options.secrets ? JSON.stringify(options.secrets) : void 0,
2684
+ created_by: (_a = options.createdBy) != null ? _a : null,
2259
2685
  status: "open"
2260
2686
  });
2261
2687
  return { taskId };
2262
2688
  }
2263
2689
  async claimTask() {
2264
2690
  return this.db.transaction(async (tx) => {
2691
+ var _a;
2265
2692
  const [task] = await tx("tasks").where({
2266
2693
  status: "open"
2267
2694
  }).limit(1).select();
@@ -2285,6 +2712,7 @@ class DatabaseTaskStore {
2285
2712
  status: "processing",
2286
2713
  lastHeartbeatAt: task.last_heartbeat_at,
2287
2714
  createdAt: task.created_at,
2715
+ createdBy: (_a = task.created_by) != null ? _a : void 0,
2288
2716
  secrets
2289
2717
  };
2290
2718
  } catch (error) {
@@ -2403,6 +2831,9 @@ class TaskManager {
2403
2831
  get secrets() {
2404
2832
  return this.task.secrets;
2405
2833
  }
2834
+ get createdBy() {
2835
+ return this.task.createdBy;
2836
+ }
2406
2837
  async getWorkspaceName() {
2407
2838
  return this.task.taskId;
2408
2839
  }
@@ -2462,7 +2893,8 @@ class StorageTaskBroker {
2462
2893
  return TaskManager.create({
2463
2894
  taskId: pendingTask.id,
2464
2895
  spec: pendingTask.spec,
2465
- secrets: pendingTask.secrets
2896
+ secrets: pendingTask.secrets,
2897
+ createdBy: pendingTask.createdBy
2466
2898
  }, this.storage, this.logger);
2467
2899
  }
2468
2900
  await this.waitForDispatch();
@@ -2613,7 +3045,8 @@ class NunjucksWorkflowRunner {
2613
3045
  await task.emitLog(`Starting up task with ${task.spec.steps.length} steps`);
2614
3046
  const context = {
2615
3047
  parameters: task.spec.parameters,
2616
- steps: {}
3048
+ steps: {},
3049
+ user: task.spec.user
2617
3050
  };
2618
3051
  for (const step of task.spec.steps) {
2619
3052
  try {
@@ -2831,10 +3264,11 @@ async function createRouter(options) {
2831
3264
  router.get("/v2/templates/:namespace/:kind/:name/parameter-schema", async (req, res) => {
2832
3265
  var _a, _b;
2833
3266
  const { namespace, kind, name } = req.params;
3267
+ const { token } = parseBearerToken(req.headers.authorization);
2834
3268
  const template = await findTemplate({
2835
3269
  catalogApi: catalogClient,
2836
3270
  entityRef: { kind, namespace, name },
2837
- token: getBearerToken(req.headers.authorization)
3271
+ token
2838
3272
  });
2839
3273
  if (isSupportedTemplate(template)) {
2840
3274
  const parameters = [(_a = template.spec.parameters) != null ? _a : []].flat();
@@ -2866,12 +3300,13 @@ async function createRouter(options) {
2866
3300
  const { kind, namespace, name } = catalogModel.parseEntityRef(templateRef, {
2867
3301
  defaultKind: "template"
2868
3302
  });
3303
+ const { token, entityRef: userEntityRef } = parseBearerToken(req.headers.authorization);
3304
+ const userEntity = userEntityRef ? await catalogClient.getEntityByRef(userEntityRef, { token }) : void 0;
2869
3305
  const values = req.body.values;
2870
- const token = getBearerToken(req.headers.authorization);
2871
3306
  const template = await findTemplate({
2872
3307
  catalogApi: catalogClient,
2873
3308
  entityRef: { kind, namespace, name },
2874
- token: getBearerToken(req.headers.authorization)
3309
+ token
2875
3310
  });
2876
3311
  if (!isSupportedTemplate(template)) {
2877
3312
  throw new errors.InputError(`Unsupported apiVersion field in schema entity, ${template.apiVersion}`);
@@ -2896,6 +3331,10 @@ async function createRouter(options) {
2896
3331
  }),
2897
3332
  output: (_b = template.spec.output) != null ? _b : {},
2898
3333
  parameters: values,
3334
+ user: {
3335
+ entity: userEntity,
3336
+ ref: userEntityRef
3337
+ },
2899
3338
  templateInfo: {
2900
3339
  entityRef: catalogModel.stringifyEntityRef({
2901
3340
  kind,
@@ -2907,6 +3346,7 @@ async function createRouter(options) {
2907
3346
  };
2908
3347
  const result = await taskBroker.dispatch({
2909
3348
  spec: taskSpec,
3349
+ createdBy: userEntityRef,
2910
3350
  secrets: {
2911
3351
  ...req.body.secrets,
2912
3352
  backstageToken: token
@@ -2981,9 +3421,17 @@ data: ${JSON.stringify(event)}
2981
3421
  app.use("/", router);
2982
3422
  return app;
2983
3423
  }
2984
- function getBearerToken(header) {
3424
+ function parseBearerToken(header) {
2985
3425
  var _a;
2986
- return (_a = header == null ? void 0 : header.match(/Bearer\s+(\S+)/i)) == null ? void 0 : _a[1];
3426
+ const token = (_a = header == null ? void 0 : header.match(/Bearer\s+(\S+)/i)) == null ? void 0 : _a[1];
3427
+ if (!token)
3428
+ return {};
3429
+ const [_header, rawPayload, _signature] = token.split(".");
3430
+ const payload = JSON.parse(Buffer.from(rawPayload, "base64").toString());
3431
+ return {
3432
+ entityRef: payload.sub,
3433
+ token
3434
+ };
2987
3435
  }
2988
3436
 
2989
3437
  class ScaffolderEntitiesProcessor {
@@ -3053,6 +3501,8 @@ exports.createGithubIssuesLabelAction = createGithubIssuesLabelAction;
3053
3501
  exports.createGithubWebhookAction = createGithubWebhookAction;
3054
3502
  exports.createPublishAzureAction = createPublishAzureAction;
3055
3503
  exports.createPublishBitbucketAction = createPublishBitbucketAction;
3504
+ exports.createPublishBitbucketCloudAction = createPublishBitbucketCloudAction;
3505
+ exports.createPublishBitbucketServerAction = createPublishBitbucketServerAction;
3056
3506
  exports.createPublishFileAction = createPublishFileAction;
3057
3507
  exports.createPublishGithubAction = createPublishGithubAction;
3058
3508
  exports.createPublishGithubPullRequestAction = createPublishGithubPullRequestAction;