@backstage/plugin-scaffolder-backend 0.17.2 → 0.18.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 +106 -2
- package/dist/index.cjs.js +96 -311
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +111 -89
- package/migrations/20210120143715_init.js +1 -1
- package/package.json +11 -13
package/dist/index.cjs.js
CHANGED
|
@@ -12,7 +12,6 @@ var path = require('path');
|
|
|
12
12
|
var globby = require('globby');
|
|
13
13
|
var isbinaryfile = require('isbinaryfile');
|
|
14
14
|
var vm2 = require('vm2');
|
|
15
|
-
var pluginScaffolderBackendModuleCookiecutter = require('@backstage/plugin-scaffolder-backend-module-cookiecutter');
|
|
16
15
|
var child_process = require('child_process');
|
|
17
16
|
var stream = require('stream');
|
|
18
17
|
var azureDevopsNodeApi = require('azure-devops-node-api');
|
|
@@ -25,10 +24,9 @@ var webhooks = require('@octokit/webhooks');
|
|
|
25
24
|
var uuid = require('uuid');
|
|
26
25
|
var luxon = require('luxon');
|
|
27
26
|
var ObservableImpl = require('zen-observable');
|
|
28
|
-
var Handlebars = require('handlebars');
|
|
29
27
|
var winston = require('winston');
|
|
30
|
-
var jsonschema = require('jsonschema');
|
|
31
28
|
var nunjucks = require('nunjucks');
|
|
29
|
+
var jsonschema = require('jsonschema');
|
|
32
30
|
var express = require('express');
|
|
33
31
|
var Router = require('express-promise-router');
|
|
34
32
|
var os = require('os');
|
|
@@ -61,7 +59,6 @@ var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
|
|
|
61
59
|
var globby__default = /*#__PURE__*/_interopDefaultLegacy(globby);
|
|
62
60
|
var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch);
|
|
63
61
|
var ObservableImpl__default = /*#__PURE__*/_interopDefaultLegacy(ObservableImpl);
|
|
64
|
-
var Handlebars__namespace = /*#__PURE__*/_interopNamespace(Handlebars);
|
|
65
62
|
var winston__namespace = /*#__PURE__*/_interopNamespace(winston);
|
|
66
63
|
var nunjucks__default = /*#__PURE__*/_interopDefaultLegacy(nunjucks);
|
|
67
64
|
var express__default = /*#__PURE__*/_interopDefaultLegacy(express);
|
|
@@ -691,7 +688,6 @@ const executeShellCommand = async (options) => {
|
|
|
691
688
|
});
|
|
692
689
|
});
|
|
693
690
|
};
|
|
694
|
-
const runCommand = executeShellCommand;
|
|
695
691
|
async function initRepoAndPush({
|
|
696
692
|
dir,
|
|
697
693
|
remoteUrl,
|
|
@@ -938,7 +934,9 @@ const createBitbucketCloudRepository = async (opts) => {
|
|
|
938
934
|
repo,
|
|
939
935
|
description,
|
|
940
936
|
repoVisibility,
|
|
941
|
-
|
|
937
|
+
mainBranch,
|
|
938
|
+
authorization,
|
|
939
|
+
apiBaseUrl
|
|
942
940
|
} = opts;
|
|
943
941
|
const options = {
|
|
944
942
|
method: "POST",
|
|
@@ -955,7 +953,7 @@ const createBitbucketCloudRepository = async (opts) => {
|
|
|
955
953
|
};
|
|
956
954
|
let response;
|
|
957
955
|
try {
|
|
958
|
-
response = await fetch__default["default"](
|
|
956
|
+
response = await fetch__default["default"](`${apiBaseUrl}/repositories/${workspace}/${repo}`, options);
|
|
959
957
|
} catch (e) {
|
|
960
958
|
throw new Error(`Unable to create repository, ${e}`);
|
|
961
959
|
}
|
|
@@ -969,12 +967,11 @@ const createBitbucketCloudRepository = async (opts) => {
|
|
|
969
967
|
remoteUrl = link.href;
|
|
970
968
|
}
|
|
971
969
|
}
|
|
972
|
-
const repoContentsUrl = `${r.links.html.href}/src
|
|
970
|
+
const repoContentsUrl = `${r.links.html.href}/src/${mainBranch}`;
|
|
973
971
|
return { remoteUrl, repoContentsUrl };
|
|
974
972
|
};
|
|
975
973
|
const createBitbucketServerRepository = async (opts) => {
|
|
976
974
|
const {
|
|
977
|
-
host,
|
|
978
975
|
project,
|
|
979
976
|
repo,
|
|
980
977
|
description,
|
|
@@ -996,8 +993,7 @@ const createBitbucketServerRepository = async (opts) => {
|
|
|
996
993
|
}
|
|
997
994
|
};
|
|
998
995
|
try {
|
|
999
|
-
|
|
1000
|
-
response = await fetch__default["default"](`${baseUrl}/projects/${project}/repos`, options);
|
|
996
|
+
response = await fetch__default["default"](`${apiBaseUrl}/projects/${project}/repos`, options);
|
|
1001
997
|
} catch (e) {
|
|
1002
998
|
throw new Error(`Unable to create repository, ${e}`);
|
|
1003
999
|
}
|
|
@@ -1117,16 +1113,20 @@ function createPublishBitbucketAction(options) {
|
|
|
1117
1113
|
if (!integrationConfig) {
|
|
1118
1114
|
throw new errors.InputError(`No matching integration configuration for host ${host}, please check your integrations config`);
|
|
1119
1115
|
}
|
|
1120
|
-
const authorization = getAuthorizationHeader(ctx.input.token ? {
|
|
1116
|
+
const authorization = getAuthorizationHeader(ctx.input.token ? {
|
|
1117
|
+
host: integrationConfig.config.host,
|
|
1118
|
+
apiBaseUrl: integrationConfig.config.apiBaseUrl,
|
|
1119
|
+
token: ctx.input.token
|
|
1120
|
+
} : integrationConfig.config);
|
|
1121
1121
|
const apiBaseUrl = integrationConfig.config.apiBaseUrl;
|
|
1122
1122
|
const createMethod = host === "bitbucket.org" ? createBitbucketCloudRepository : createBitbucketServerRepository;
|
|
1123
1123
|
const { remoteUrl, repoContentsUrl } = await createMethod({
|
|
1124
1124
|
authorization,
|
|
1125
|
-
host,
|
|
1126
1125
|
workspace: workspace || "",
|
|
1127
1126
|
project,
|
|
1128
1127
|
repo,
|
|
1129
1128
|
repoVisibility,
|
|
1129
|
+
mainBranch: defaultBranch,
|
|
1130
1130
|
description,
|
|
1131
1131
|
apiBaseUrl
|
|
1132
1132
|
});
|
|
@@ -1192,10 +1192,14 @@ function createPublishFileAction() {
|
|
|
1192
1192
|
});
|
|
1193
1193
|
}
|
|
1194
1194
|
|
|
1195
|
+
const DEFAULT_TIMEOUT_MS = 6e4;
|
|
1195
1196
|
async function getOctokitOptions(options) {
|
|
1196
1197
|
var _a;
|
|
1197
1198
|
const { integrations, credentialsProvider, repoUrl, token } = options;
|
|
1198
1199
|
const { owner, repo, host } = parseRepoUrl(repoUrl, integrations);
|
|
1200
|
+
const requestOptions = {
|
|
1201
|
+
timeout: DEFAULT_TIMEOUT_MS
|
|
1202
|
+
};
|
|
1199
1203
|
if (!owner) {
|
|
1200
1204
|
throw new errors.InputError(`No owner provided for repo ${repoUrl}`);
|
|
1201
1205
|
}
|
|
@@ -1207,7 +1211,8 @@ async function getOctokitOptions(options) {
|
|
|
1207
1211
|
return {
|
|
1208
1212
|
auth: token,
|
|
1209
1213
|
baseUrl: integrationConfig.apiBaseUrl,
|
|
1210
|
-
previews: ["nebula-preview"]
|
|
1214
|
+
previews: ["nebula-preview"],
|
|
1215
|
+
request: requestOptions
|
|
1211
1216
|
};
|
|
1212
1217
|
}
|
|
1213
1218
|
const githubCredentialsProvider = credentialsProvider != null ? credentialsProvider : integration.DefaultGithubCredentialsProvider.fromIntegrations(integrations);
|
|
@@ -1263,6 +1268,26 @@ function createPublishGithubAction(options) {
|
|
|
1263
1268
|
type: "string",
|
|
1264
1269
|
description: `Sets the default branch on the repository. The default value is 'master'`
|
|
1265
1270
|
},
|
|
1271
|
+
deleteBranchOnMerge: {
|
|
1272
|
+
title: "Delete Branch On Merge",
|
|
1273
|
+
type: "boolean",
|
|
1274
|
+
description: `Delete the branch after merging the PR. The default value is 'false'`
|
|
1275
|
+
},
|
|
1276
|
+
allowMergeCommit: {
|
|
1277
|
+
title: "Allow Merge Commits",
|
|
1278
|
+
type: "boolean",
|
|
1279
|
+
description: `Allow merge commits. The default value is 'true'`
|
|
1280
|
+
},
|
|
1281
|
+
allowSquashMerge: {
|
|
1282
|
+
title: "Allow Squash Merges",
|
|
1283
|
+
type: "boolean",
|
|
1284
|
+
description: `Allow squash merges. The default value is 'true'`
|
|
1285
|
+
},
|
|
1286
|
+
allowRebaseMerge: {
|
|
1287
|
+
title: "Allow Rebase Merges",
|
|
1288
|
+
type: "boolean",
|
|
1289
|
+
description: `Allow rebase merges. The default value is 'true'`
|
|
1290
|
+
},
|
|
1266
1291
|
sourcePath: {
|
|
1267
1292
|
title: "Source Path",
|
|
1268
1293
|
description: "Path within the workspace that will be used as the repository root. If omitted, the entire workspace will be published as the repository.",
|
|
@@ -1324,6 +1349,10 @@ function createPublishGithubAction(options) {
|
|
|
1324
1349
|
requireCodeOwnerReviews = false,
|
|
1325
1350
|
repoVisibility = "private",
|
|
1326
1351
|
defaultBranch = "master",
|
|
1352
|
+
deleteBranchOnMerge = false,
|
|
1353
|
+
allowMergeCommit = true,
|
|
1354
|
+
allowSquashMerge = true,
|
|
1355
|
+
allowRebaseMerge = true,
|
|
1327
1356
|
collaborators,
|
|
1328
1357
|
topics,
|
|
1329
1358
|
token: providedToken
|
|
@@ -1347,11 +1376,19 @@ function createPublishGithubAction(options) {
|
|
|
1347
1376
|
org: owner,
|
|
1348
1377
|
private: repoVisibility === "private",
|
|
1349
1378
|
visibility: repoVisibility,
|
|
1350
|
-
description
|
|
1379
|
+
description,
|
|
1380
|
+
delete_branch_on_merge: deleteBranchOnMerge,
|
|
1381
|
+
allow_merge_commit: allowMergeCommit,
|
|
1382
|
+
allow_squash_merge: allowSquashMerge,
|
|
1383
|
+
allow_rebase_merge: allowRebaseMerge
|
|
1351
1384
|
}) : client.rest.repos.createForAuthenticatedUser({
|
|
1352
1385
|
name: repo,
|
|
1353
1386
|
private: repoVisibility === "private",
|
|
1354
|
-
description
|
|
1387
|
+
description,
|
|
1388
|
+
delete_branch_on_merge: deleteBranchOnMerge,
|
|
1389
|
+
allow_merge_commit: allowMergeCommit,
|
|
1390
|
+
allow_squash_merge: allowSquashMerge,
|
|
1391
|
+
allow_rebase_merge: allowRebaseMerge
|
|
1355
1392
|
});
|
|
1356
1393
|
const { data: newRepo } = await repoCreationPromise;
|
|
1357
1394
|
if (access == null ? void 0 : access.startsWith(`${owner}/`)) {
|
|
@@ -2001,49 +2038,10 @@ function createGithubWebhookAction(options) {
|
|
|
2001
2038
|
});
|
|
2002
2039
|
}
|
|
2003
2040
|
|
|
2004
|
-
class OctokitProvider {
|
|
2005
|
-
constructor(integrations, githubCredentialsProvider) {
|
|
2006
|
-
this.integrations = integrations;
|
|
2007
|
-
this.githubCredentialsProvider = githubCredentialsProvider || integration.DefaultGithubCredentialsProvider.fromIntegrations(this.integrations);
|
|
2008
|
-
}
|
|
2009
|
-
async getOctokit(repoUrl, options) {
|
|
2010
|
-
var _a;
|
|
2011
|
-
const { owner, repo, host } = parseRepoUrl(repoUrl, this.integrations);
|
|
2012
|
-
if (!owner) {
|
|
2013
|
-
throw new errors.InputError(`No owner provided for repo ${repoUrl}`);
|
|
2014
|
-
}
|
|
2015
|
-
const integrationConfig = (_a = this.integrations.github.byHost(host)) == null ? void 0 : _a.config;
|
|
2016
|
-
if (!integrationConfig) {
|
|
2017
|
-
throw new errors.InputError(`No integration for host ${host}`);
|
|
2018
|
-
}
|
|
2019
|
-
if (options == null ? void 0 : options.token) {
|
|
2020
|
-
const client2 = new octokit.Octokit({
|
|
2021
|
-
auth: options.token,
|
|
2022
|
-
baseUrl: integrationConfig.apiBaseUrl,
|
|
2023
|
-
previews: ["nebula-preview"]
|
|
2024
|
-
});
|
|
2025
|
-
return { client: client2, token: options.token, owner, repo };
|
|
2026
|
-
}
|
|
2027
|
-
const { token } = await this.githubCredentialsProvider.getCredentials({
|
|
2028
|
-
url: `https://${host}/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}`
|
|
2029
|
-
});
|
|
2030
|
-
if (!token) {
|
|
2031
|
-
throw new errors.InputError(`No token available for host: ${host}, with owner ${owner}, and repo ${repo}`);
|
|
2032
|
-
}
|
|
2033
|
-
const client = new octokit.Octokit({
|
|
2034
|
-
auth: token,
|
|
2035
|
-
baseUrl: integrationConfig.apiBaseUrl,
|
|
2036
|
-
previews: ["nebula-preview"]
|
|
2037
|
-
});
|
|
2038
|
-
return { client, token, owner, repo };
|
|
2039
|
-
}
|
|
2040
|
-
}
|
|
2041
|
-
|
|
2042
2041
|
const createBuiltinActions = (options) => {
|
|
2043
2042
|
const {
|
|
2044
2043
|
reader,
|
|
2045
2044
|
integrations,
|
|
2046
|
-
containerRunner,
|
|
2047
2045
|
catalogClient,
|
|
2048
2046
|
config,
|
|
2049
2047
|
additionalTemplateFilters
|
|
@@ -2097,16 +2095,6 @@ const createBuiltinActions = (options) => {
|
|
|
2097
2095
|
githubCredentialsProvider
|
|
2098
2096
|
})
|
|
2099
2097
|
];
|
|
2100
|
-
if (containerRunner) {
|
|
2101
|
-
backendCommon.getRootLogger().warn(`[DEPRECATED] The fetch:cookiecutter action will be removed part of the default scaffolder actions in later versions.
|
|
2102
|
-
You can install the package seperately and remove the containerRunner from the createBuiltInActions to remove this warning,
|
|
2103
|
-
or you can migrate to using fetch:template https://backstage.io/docs/features/software-templates/builtin-actions#migrating-from-fetchcookiecutter-to-fetchtemplate`);
|
|
2104
|
-
actions.push(pluginScaffolderBackendModuleCookiecutter.createFetchCookiecutterAction({
|
|
2105
|
-
reader,
|
|
2106
|
-
integrations,
|
|
2107
|
-
containerRunner
|
|
2108
|
-
}));
|
|
2109
|
-
}
|
|
2110
2098
|
return actions;
|
|
2111
2099
|
};
|
|
2112
2100
|
|
|
@@ -2214,7 +2202,7 @@ class DatabaseTaskStore {
|
|
|
2214
2202
|
}
|
|
2215
2203
|
}
|
|
2216
2204
|
async listStaleTasks({ timeoutS }) {
|
|
2217
|
-
const rawRows = await this.db("tasks").where("status", "processing").andWhere("last_heartbeat_at", "<=", this.db.client.config.client
|
|
2205
|
+
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', ?, ?)`, [
|
|
2218
2206
|
`-${timeoutS}`,
|
|
2219
2207
|
this.db.fn.now()
|
|
2220
2208
|
]));
|
|
@@ -2441,182 +2429,6 @@ function isTruthy(value) {
|
|
|
2441
2429
|
return lodash.isArray(value) ? value.length > 0 : !!value;
|
|
2442
2430
|
}
|
|
2443
2431
|
|
|
2444
|
-
const isValidTaskSpec$1 = (taskSpec) => taskSpec.apiVersion === "backstage.io/v1beta2";
|
|
2445
|
-
class HandlebarsWorkflowRunner {
|
|
2446
|
-
constructor(options) {
|
|
2447
|
-
this.options = options;
|
|
2448
|
-
this.handlebars = Handlebars__namespace.create();
|
|
2449
|
-
this.handlebars.registerHelper("parseRepoUrl", (repoUrl) => {
|
|
2450
|
-
return JSON.stringify(parseRepoUrl(repoUrl, this.options.integrations));
|
|
2451
|
-
});
|
|
2452
|
-
this.handlebars.registerHelper("projectSlug", (repoUrl) => {
|
|
2453
|
-
const { owner, repo } = parseRepoUrl(repoUrl, this.options.integrations);
|
|
2454
|
-
return `${owner}/${repo}`;
|
|
2455
|
-
});
|
|
2456
|
-
this.handlebars.registerHelper("json", (obj) => JSON.stringify(obj));
|
|
2457
|
-
this.handlebars.registerHelper("not", (value) => !isTruthy(value));
|
|
2458
|
-
this.handlebars.registerHelper("eq", (a, b) => a === b);
|
|
2459
|
-
}
|
|
2460
|
-
async execute(task) {
|
|
2461
|
-
var _a, _b;
|
|
2462
|
-
if (!isValidTaskSpec$1(task.spec)) {
|
|
2463
|
-
throw new errors.InputError(`Task spec is not a valid v1beta2 task spec`);
|
|
2464
|
-
}
|
|
2465
|
-
const { actionRegistry } = this.options;
|
|
2466
|
-
const workspacePath = path__default["default"].join(this.options.workingDirectory, await task.getWorkspaceName());
|
|
2467
|
-
try {
|
|
2468
|
-
await fs__default["default"].ensureDir(workspacePath);
|
|
2469
|
-
await task.emitLog(`Starting up task with ${task.spec.steps.length} steps`);
|
|
2470
|
-
const templateCtx = { parameters: task.spec.values, steps: {} };
|
|
2471
|
-
for (const step of task.spec.steps) {
|
|
2472
|
-
const metadata = { stepId: step.id };
|
|
2473
|
-
try {
|
|
2474
|
-
const taskLogger = winston__namespace.createLogger({
|
|
2475
|
-
level: process.env.LOG_LEVEL || "info",
|
|
2476
|
-
format: winston__namespace.format.combine(winston__namespace.format.colorize(), winston__namespace.format.timestamp(), winston__namespace.format.simple()),
|
|
2477
|
-
defaultMeta: {}
|
|
2478
|
-
});
|
|
2479
|
-
const stream$1 = new stream.PassThrough();
|
|
2480
|
-
stream$1.on("data", async (data) => {
|
|
2481
|
-
const message = data.toString().trim();
|
|
2482
|
-
if ((message == null ? void 0 : message.length) > 1) {
|
|
2483
|
-
await task.emitLog(message, metadata);
|
|
2484
|
-
}
|
|
2485
|
-
});
|
|
2486
|
-
taskLogger.add(new winston__namespace.transports.Stream({ stream: stream$1 }));
|
|
2487
|
-
if (step.if !== void 0) {
|
|
2488
|
-
let skip = !step.if;
|
|
2489
|
-
if (typeof step.if === "string") {
|
|
2490
|
-
const condition = JSON.parse(JSON.stringify(step.if), (_key, value) => {
|
|
2491
|
-
if (typeof value === "string") {
|
|
2492
|
-
const templated = this.handlebars.compile(value, {
|
|
2493
|
-
noEscape: true,
|
|
2494
|
-
data: false,
|
|
2495
|
-
preventIndent: true
|
|
2496
|
-
})(templateCtx);
|
|
2497
|
-
if (templated === "") {
|
|
2498
|
-
return void 0;
|
|
2499
|
-
}
|
|
2500
|
-
try {
|
|
2501
|
-
return JSON.parse(templated);
|
|
2502
|
-
} catch {
|
|
2503
|
-
return templated;
|
|
2504
|
-
}
|
|
2505
|
-
}
|
|
2506
|
-
return value;
|
|
2507
|
-
});
|
|
2508
|
-
skip = !isTruthy(condition);
|
|
2509
|
-
}
|
|
2510
|
-
if (skip) {
|
|
2511
|
-
await task.emitLog(`Skipped step ${step.name}`, {
|
|
2512
|
-
...metadata,
|
|
2513
|
-
status: "skipped"
|
|
2514
|
-
});
|
|
2515
|
-
continue;
|
|
2516
|
-
}
|
|
2517
|
-
}
|
|
2518
|
-
await task.emitLog(`Beginning step ${step.name}`, {
|
|
2519
|
-
...metadata,
|
|
2520
|
-
status: "processing"
|
|
2521
|
-
});
|
|
2522
|
-
const action = actionRegistry.get(step.action);
|
|
2523
|
-
if (!action) {
|
|
2524
|
-
throw new Error(`Action '${step.action}' does not exist`);
|
|
2525
|
-
}
|
|
2526
|
-
const input = step.input && JSON.parse(JSON.stringify(step.input), (_key, value) => {
|
|
2527
|
-
if (typeof value === "string") {
|
|
2528
|
-
const templated = this.handlebars.compile(value, {
|
|
2529
|
-
noEscape: true,
|
|
2530
|
-
data: false,
|
|
2531
|
-
preventIndent: true
|
|
2532
|
-
})(templateCtx);
|
|
2533
|
-
if (templated.startsWith('"') && templated.endsWith('"') || templated.startsWith("{") && templated.endsWith("}") || templated.startsWith("[") && templated.endsWith("]")) {
|
|
2534
|
-
try {
|
|
2535
|
-
return JSON.parse(templated);
|
|
2536
|
-
} catch {
|
|
2537
|
-
return templated;
|
|
2538
|
-
}
|
|
2539
|
-
}
|
|
2540
|
-
return templated;
|
|
2541
|
-
}
|
|
2542
|
-
return value;
|
|
2543
|
-
});
|
|
2544
|
-
if ((_a = action.schema) == null ? void 0 : _a.input) {
|
|
2545
|
-
const validateResult = jsonschema.validate(input, action.schema.input);
|
|
2546
|
-
if (!validateResult.valid) {
|
|
2547
|
-
const errors$1 = validateResult.errors.join(", ");
|
|
2548
|
-
throw new errors.InputError(`Invalid input passed to action ${action.id}, ${errors$1}`);
|
|
2549
|
-
}
|
|
2550
|
-
}
|
|
2551
|
-
const stepOutputs = {};
|
|
2552
|
-
const tmpDirs = new Array();
|
|
2553
|
-
this.options.logger.debug(`Running ${action.id} with input`, {
|
|
2554
|
-
input: JSON.stringify(input, null, 2)
|
|
2555
|
-
});
|
|
2556
|
-
await action.handler({
|
|
2557
|
-
baseUrl: task.spec.baseUrl,
|
|
2558
|
-
logger: taskLogger,
|
|
2559
|
-
logStream: stream$1,
|
|
2560
|
-
input,
|
|
2561
|
-
secrets: (_b = task.secrets) != null ? _b : {},
|
|
2562
|
-
workspacePath,
|
|
2563
|
-
async createTemporaryDirectory() {
|
|
2564
|
-
const tmpDir = await fs__default["default"].mkdtemp(`${workspacePath}_step-${step.id}-`);
|
|
2565
|
-
tmpDirs.push(tmpDir);
|
|
2566
|
-
return tmpDir;
|
|
2567
|
-
},
|
|
2568
|
-
output(name, value) {
|
|
2569
|
-
stepOutputs[name] = value;
|
|
2570
|
-
},
|
|
2571
|
-
metadata: task.spec.metadata,
|
|
2572
|
-
templateInfo: task.spec.templateInfo
|
|
2573
|
-
});
|
|
2574
|
-
for (const tmpDir of tmpDirs) {
|
|
2575
|
-
await fs__default["default"].remove(tmpDir);
|
|
2576
|
-
}
|
|
2577
|
-
templateCtx.steps[step.id] = { output: stepOutputs };
|
|
2578
|
-
await task.emitLog(`Finished step ${step.name}`, {
|
|
2579
|
-
...metadata,
|
|
2580
|
-
status: "completed"
|
|
2581
|
-
});
|
|
2582
|
-
} catch (error) {
|
|
2583
|
-
await task.emitLog(String(error.stack), {
|
|
2584
|
-
...metadata,
|
|
2585
|
-
status: "failed"
|
|
2586
|
-
});
|
|
2587
|
-
throw error;
|
|
2588
|
-
}
|
|
2589
|
-
}
|
|
2590
|
-
const output = JSON.parse(JSON.stringify(task.spec.output), (_key, value) => {
|
|
2591
|
-
if (typeof value === "string") {
|
|
2592
|
-
const templated = this.handlebars.compile(value, {
|
|
2593
|
-
noEscape: true,
|
|
2594
|
-
data: false,
|
|
2595
|
-
preventIndent: true
|
|
2596
|
-
})(templateCtx);
|
|
2597
|
-
if (templated === "") {
|
|
2598
|
-
return void 0;
|
|
2599
|
-
}
|
|
2600
|
-
if (templated.startsWith('"') && templated.endsWith('"') || templated.startsWith("{") && templated.endsWith("}") || templated.startsWith("[") && templated.endsWith("]")) {
|
|
2601
|
-
try {
|
|
2602
|
-
return JSON.parse(templated);
|
|
2603
|
-
} catch {
|
|
2604
|
-
return templated;
|
|
2605
|
-
}
|
|
2606
|
-
}
|
|
2607
|
-
return templated;
|
|
2608
|
-
}
|
|
2609
|
-
return value;
|
|
2610
|
-
});
|
|
2611
|
-
return { output };
|
|
2612
|
-
} finally {
|
|
2613
|
-
if (workspacePath) {
|
|
2614
|
-
await fs__default["default"].remove(workspacePath);
|
|
2615
|
-
}
|
|
2616
|
-
}
|
|
2617
|
-
}
|
|
2618
|
-
}
|
|
2619
|
-
|
|
2620
2432
|
const isValidTaskSpec = (taskSpec) => {
|
|
2621
2433
|
return taskSpec.apiVersion === "scaffolder.backstage.io/v1beta3";
|
|
2622
2434
|
};
|
|
@@ -2730,7 +2542,6 @@ class NunjucksWorkflowRunner {
|
|
|
2730
2542
|
const tmpDirs = new Array();
|
|
2731
2543
|
const stepOutput = {};
|
|
2732
2544
|
await action.handler({
|
|
2733
|
-
baseUrl: task.spec.baseUrl,
|
|
2734
2545
|
input,
|
|
2735
2546
|
secrets: (_d = task.secrets) != null ? _d : {},
|
|
2736
2547
|
logger: taskLogger,
|
|
@@ -2744,7 +2555,6 @@ class NunjucksWorkflowRunner {
|
|
|
2744
2555
|
output(name, value) {
|
|
2745
2556
|
stepOutput[name] = value;
|
|
2746
2557
|
},
|
|
2747
|
-
metadata: task.spec.metadata,
|
|
2748
2558
|
templateInfo: task.spec.templateInfo
|
|
2749
2559
|
});
|
|
2750
2560
|
for (const tmpDir of tmpDirs) {
|
|
@@ -2786,12 +2596,6 @@ class TaskWorker {
|
|
|
2786
2596
|
workingDirectory,
|
|
2787
2597
|
additionalTemplateFilters
|
|
2788
2598
|
} = options;
|
|
2789
|
-
const legacyWorkflowRunner = new HandlebarsWorkflowRunner({
|
|
2790
|
-
logger,
|
|
2791
|
-
actionRegistry,
|
|
2792
|
-
integrations,
|
|
2793
|
-
workingDirectory
|
|
2794
|
-
});
|
|
2795
2599
|
const workflowRunner = new NunjucksWorkflowRunner({
|
|
2796
2600
|
actionRegistry,
|
|
2797
2601
|
integrations,
|
|
@@ -2801,7 +2605,7 @@ class TaskWorker {
|
|
|
2801
2605
|
});
|
|
2802
2606
|
return new TaskWorker({
|
|
2803
2607
|
taskBroker,
|
|
2804
|
-
runners: {
|
|
2608
|
+
runners: { workflowRunner }
|
|
2805
2609
|
});
|
|
2806
2610
|
}
|
|
2807
2611
|
start() {
|
|
@@ -2814,7 +2618,10 @@ class TaskWorker {
|
|
|
2814
2618
|
}
|
|
2815
2619
|
async runOneTask(task) {
|
|
2816
2620
|
try {
|
|
2817
|
-
|
|
2621
|
+
if (task.spec.apiVersion !== "scaffolder.backstage.io/v1beta3") {
|
|
2622
|
+
throw new Error(`Unsupported Template apiVersion ${task.spec.apiVersion}`);
|
|
2623
|
+
}
|
|
2624
|
+
const { output } = await this.options.runners.workflowRunner.execute(task);
|
|
2818
2625
|
await task.complete("completed", { output });
|
|
2819
2626
|
} catch (error) {
|
|
2820
2627
|
errors.assertError(error);
|
|
@@ -2865,15 +2672,15 @@ async function findTemplate(options) {
|
|
|
2865
2672
|
if (entityRef.kind.toLocaleLowerCase("en-US") !== "template") {
|
|
2866
2673
|
throw new errors.InputError(`Invalid kind, only 'Template' kind is supported`);
|
|
2867
2674
|
}
|
|
2868
|
-
const template = await catalogApi.
|
|
2675
|
+
const template = await catalogApi.getEntityByRef(entityRef, { token });
|
|
2869
2676
|
if (!template) {
|
|
2870
|
-
throw new errors.NotFoundError(`Template ${entityRef} not found`);
|
|
2677
|
+
throw new errors.NotFoundError(`Template ${catalogModel.stringifyEntityRef(entityRef)} not found`);
|
|
2871
2678
|
}
|
|
2872
2679
|
return template;
|
|
2873
2680
|
}
|
|
2874
2681
|
|
|
2875
2682
|
function isSupportedTemplate(entity) {
|
|
2876
|
-
return entity.apiVersion === "
|
|
2683
|
+
return entity.apiVersion === "scaffolder.backstage.io/v1beta3";
|
|
2877
2684
|
}
|
|
2878
2685
|
async function createRouter(options) {
|
|
2879
2686
|
const router = Router__default["default"]();
|
|
@@ -2885,7 +2692,6 @@ async function createRouter(options) {
|
|
|
2885
2692
|
database,
|
|
2886
2693
|
catalogClient,
|
|
2887
2694
|
actions,
|
|
2888
|
-
containerRunner,
|
|
2889
2695
|
taskWorkers,
|
|
2890
2696
|
additionalTemplateFilters
|
|
2891
2697
|
} = options;
|
|
@@ -2917,7 +2723,6 @@ async function createRouter(options) {
|
|
|
2917
2723
|
const actionsToRegister = Array.isArray(actions) ? actions : createBuiltinActions({
|
|
2918
2724
|
integrations,
|
|
2919
2725
|
catalogClient,
|
|
2920
|
-
containerRunner,
|
|
2921
2726
|
reader,
|
|
2922
2727
|
config,
|
|
2923
2728
|
additionalTemplateFilters
|
|
@@ -2957,7 +2762,7 @@ async function createRouter(options) {
|
|
|
2957
2762
|
});
|
|
2958
2763
|
res.json(actionsList);
|
|
2959
2764
|
}).post("/v2/tasks", async (req, res) => {
|
|
2960
|
-
var _a, _b, _c
|
|
2765
|
+
var _a, _b, _c;
|
|
2961
2766
|
const templateRef = req.body.templateRef;
|
|
2962
2767
|
const { kind, namespace, name } = catalogModel.parseEntityRef(templateRef, {
|
|
2963
2768
|
defaultKind: "template"
|
|
@@ -2969,52 +2774,38 @@ async function createRouter(options) {
|
|
|
2969
2774
|
entityRef: { kind, namespace, name },
|
|
2970
2775
|
token: getBearerToken(req.headers.authorization)
|
|
2971
2776
|
});
|
|
2972
|
-
|
|
2973
|
-
if (isSupportedTemplate(template)) {
|
|
2974
|
-
if (template.apiVersion === "backstage.io/v1beta2") {
|
|
2975
|
-
logger.warn(`Scaffolding ${catalogModel.stringifyEntityRef(template)} with deprecated apiVersion ${template.apiVersion}. Please migrate the template to backstage.io/v1beta3. https://backstage.io/docs/features/software-templates/migrating-from-v1beta2-to-v1beta3`);
|
|
2976
|
-
}
|
|
2977
|
-
for (const parameters of [(_a = template.spec.parameters) != null ? _a : []].flat()) {
|
|
2978
|
-
const result2 = jsonschema.validate(values, parameters);
|
|
2979
|
-
if (!result2.valid) {
|
|
2980
|
-
res.status(400).json({ errors: result2.errors });
|
|
2981
|
-
return;
|
|
2982
|
-
}
|
|
2983
|
-
}
|
|
2984
|
-
const baseUrl = getEntityBaseUrl(template);
|
|
2985
|
-
const baseTaskSpec = {
|
|
2986
|
-
baseUrl,
|
|
2987
|
-
steps: template.spec.steps.map((step, index) => {
|
|
2988
|
-
var _a2, _b2;
|
|
2989
|
-
return {
|
|
2990
|
-
...step,
|
|
2991
|
-
id: (_a2 = step.id) != null ? _a2 : `step-${index + 1}`,
|
|
2992
|
-
name: (_b2 = step.name) != null ? _b2 : step.action
|
|
2993
|
-
};
|
|
2994
|
-
}),
|
|
2995
|
-
output: (_b = template.spec.output) != null ? _b : {},
|
|
2996
|
-
metadata: { name: (_c = template.metadata) == null ? void 0 : _c.name },
|
|
2997
|
-
templateInfo: {
|
|
2998
|
-
entityRef: catalogModel.stringifyEntityRef({
|
|
2999
|
-
kind,
|
|
3000
|
-
namespace,
|
|
3001
|
-
name: (_d = template.metadata) == null ? void 0 : _d.name
|
|
3002
|
-
}),
|
|
3003
|
-
baseUrl
|
|
3004
|
-
}
|
|
3005
|
-
};
|
|
3006
|
-
taskSpec = template.apiVersion === "backstage.io/v1beta2" ? {
|
|
3007
|
-
...baseTaskSpec,
|
|
3008
|
-
apiVersion: template.apiVersion,
|
|
3009
|
-
values
|
|
3010
|
-
} : {
|
|
3011
|
-
...baseTaskSpec,
|
|
3012
|
-
apiVersion: template.apiVersion,
|
|
3013
|
-
parameters: values
|
|
3014
|
-
};
|
|
3015
|
-
} else {
|
|
2777
|
+
if (!isSupportedTemplate(template)) {
|
|
3016
2778
|
throw new errors.InputError(`Unsupported apiVersion field in schema entity, ${template.apiVersion}`);
|
|
3017
2779
|
}
|
|
2780
|
+
for (const parameters of [(_a = template.spec.parameters) != null ? _a : []].flat()) {
|
|
2781
|
+
const result2 = jsonschema.validate(values, parameters);
|
|
2782
|
+
if (!result2.valid) {
|
|
2783
|
+
res.status(400).json({ errors: result2.errors });
|
|
2784
|
+
return;
|
|
2785
|
+
}
|
|
2786
|
+
}
|
|
2787
|
+
const baseUrl = getEntityBaseUrl(template);
|
|
2788
|
+
const taskSpec = {
|
|
2789
|
+
apiVersion: template.apiVersion,
|
|
2790
|
+
steps: template.spec.steps.map((step, index) => {
|
|
2791
|
+
var _a2, _b2;
|
|
2792
|
+
return {
|
|
2793
|
+
...step,
|
|
2794
|
+
id: (_a2 = step.id) != null ? _a2 : `step-${index + 1}`,
|
|
2795
|
+
name: (_b2 = step.name) != null ? _b2 : step.action
|
|
2796
|
+
};
|
|
2797
|
+
}),
|
|
2798
|
+
output: (_b = template.spec.output) != null ? _b : {},
|
|
2799
|
+
parameters: values,
|
|
2800
|
+
templateInfo: {
|
|
2801
|
+
entityRef: catalogModel.stringifyEntityRef({
|
|
2802
|
+
kind,
|
|
2803
|
+
namespace,
|
|
2804
|
+
name: (_c = template.metadata) == null ? void 0 : _c.name
|
|
2805
|
+
}),
|
|
2806
|
+
baseUrl
|
|
2807
|
+
}
|
|
2808
|
+
};
|
|
3018
2809
|
const result = await taskBroker.dispatch({
|
|
3019
2810
|
spec: taskSpec,
|
|
3020
2811
|
secrets: {
|
|
@@ -3112,7 +2903,7 @@ class ScaffolderEntitiesProcessor {
|
|
|
3112
2903
|
return false;
|
|
3113
2904
|
}
|
|
3114
2905
|
async postProcessEntity(entity, _location, emit) {
|
|
3115
|
-
const selfRef = catalogModel.
|
|
2906
|
+
const selfRef = catalogModel.getCompoundEntityRef(entity);
|
|
3116
2907
|
if (entity.apiVersion === "scaffolder.backstage.io/v1beta3" && entity.kind === "Template") {
|
|
3117
2908
|
const template = entity;
|
|
3118
2909
|
const target = template.spec.owner;
|
|
@@ -3121,7 +2912,7 @@ class ScaffolderEntitiesProcessor {
|
|
|
3121
2912
|
defaultKind: "Group",
|
|
3122
2913
|
defaultNamespace: selfRef.namespace
|
|
3123
2914
|
});
|
|
3124
|
-
emit(pluginCatalogBackend.
|
|
2915
|
+
emit(pluginCatalogBackend.processingResult.relation({
|
|
3125
2916
|
source: selfRef,
|
|
3126
2917
|
type: catalogModel.RELATION_OWNED_BY,
|
|
3127
2918
|
target: {
|
|
@@ -3130,7 +2921,7 @@ class ScaffolderEntitiesProcessor {
|
|
|
3130
2921
|
name: targetRef.name
|
|
3131
2922
|
}
|
|
3132
2923
|
}));
|
|
3133
|
-
emit(pluginCatalogBackend.
|
|
2924
|
+
emit(pluginCatalogBackend.processingResult.relation({
|
|
3134
2925
|
source: {
|
|
3135
2926
|
kind: targetRef.kind,
|
|
3136
2927
|
namespace: targetRef.namespace,
|
|
@@ -3145,12 +2936,7 @@ class ScaffolderEntitiesProcessor {
|
|
|
3145
2936
|
}
|
|
3146
2937
|
}
|
|
3147
2938
|
|
|
3148
|
-
Object.defineProperty(exports, 'createFetchCookiecutterAction', {
|
|
3149
|
-
enumerable: true,
|
|
3150
|
-
get: function () { return pluginScaffolderBackendModuleCookiecutter.createFetchCookiecutterAction; }
|
|
3151
|
-
});
|
|
3152
2939
|
exports.DatabaseTaskStore = DatabaseTaskStore;
|
|
3153
|
-
exports.OctokitProvider = OctokitProvider;
|
|
3154
2940
|
exports.ScaffolderEntitiesProcessor = ScaffolderEntitiesProcessor;
|
|
3155
2941
|
exports.TaskManager = TaskManager;
|
|
3156
2942
|
exports.TaskWorker = TaskWorker;
|
|
@@ -3176,5 +2962,4 @@ exports.createRouter = createRouter;
|
|
|
3176
2962
|
exports.createTemplateAction = createTemplateAction;
|
|
3177
2963
|
exports.executeShellCommand = executeShellCommand;
|
|
3178
2964
|
exports.fetchContents = fetchContents;
|
|
3179
|
-
exports.runCommand = runCommand;
|
|
3180
2965
|
//# sourceMappingURL=index.cjs.js.map
|