@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/CHANGELOG.md +88 -0
- package/dist/index.cjs.js +473 -23
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +56 -1
- package/migrations/20220129100000_created_by.js +38 -0
- package/package.json +12 -12
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: {
|
|
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 {
|
|
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
|
|
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
|
|
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
|
|
3424
|
+
function parseBearerToken(header) {
|
|
2985
3425
|
var _a;
|
|
2986
|
-
|
|
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;
|