@backstage/plugin-scaffolder-backend 1.12.0 → 1.12.1-next.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 +24 -0
- package/alpha/package.json +1 -1
- package/dist/alpha.cjs.js +347 -150
- package/dist/alpha.cjs.js.map +1 -1
- package/dist/index.cjs.js +348 -150
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +31 -7
- package/package.json +14 -11
package/dist/index.cjs.js
CHANGED
|
@@ -11,6 +11,7 @@ var backendCommon = require('@backstage/backend-common');
|
|
|
11
11
|
var zod = require('zod');
|
|
12
12
|
var integration = require('@backstage/integration');
|
|
13
13
|
var path = require('path');
|
|
14
|
+
var luxon = require('luxon');
|
|
14
15
|
var globby = require('globby');
|
|
15
16
|
var isbinaryfile = require('isbinaryfile');
|
|
16
17
|
var vm2 = require('vm2');
|
|
@@ -26,7 +27,6 @@ var fs$1 = require('fs');
|
|
|
26
27
|
var limiterFactory = require('p-limit');
|
|
27
28
|
var node = require('@gitbeaker/node');
|
|
28
29
|
var uuid = require('uuid');
|
|
29
|
-
var luxon = require('luxon');
|
|
30
30
|
var ObservableImpl = require('zen-observable');
|
|
31
31
|
var PQueue = require('p-queue');
|
|
32
32
|
var winston = require('winston');
|
|
@@ -39,7 +39,7 @@ var express = require('express');
|
|
|
39
39
|
var Router = require('express-promise-router');
|
|
40
40
|
var url = require('url');
|
|
41
41
|
var os = require('os');
|
|
42
|
-
var
|
|
42
|
+
var pluginCatalogNode = require('@backstage/plugin-catalog-node');
|
|
43
43
|
|
|
44
44
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
45
45
|
|
|
@@ -77,14 +77,14 @@ var express__default = /*#__PURE__*/_interopDefaultLegacy(express);
|
|
|
77
77
|
var Router__default = /*#__PURE__*/_interopDefaultLegacy(Router);
|
|
78
78
|
var os__default = /*#__PURE__*/_interopDefaultLegacy(os);
|
|
79
79
|
|
|
80
|
-
const id$
|
|
81
|
-
const examples$
|
|
80
|
+
const id$4 = "catalog:register";
|
|
81
|
+
const examples$4 = [
|
|
82
82
|
{
|
|
83
83
|
description: "Register with the catalog",
|
|
84
84
|
example: yaml__default["default"].stringify({
|
|
85
85
|
steps: [
|
|
86
86
|
{
|
|
87
|
-
action: id$
|
|
87
|
+
action: id$4,
|
|
88
88
|
id: "register-with-catalog",
|
|
89
89
|
name: "Register with the catalog",
|
|
90
90
|
input: {
|
|
@@ -98,9 +98,9 @@ const examples$3 = [
|
|
|
98
98
|
function createCatalogRegisterAction(options) {
|
|
99
99
|
const { catalogClient, integrations } = options;
|
|
100
100
|
return pluginScaffolderNode.createTemplateAction({
|
|
101
|
-
id: id$
|
|
101
|
+
id: id$4,
|
|
102
102
|
description: "Registers entities from a catalog descriptor file in the workspace into the software catalog.",
|
|
103
|
-
examples: examples$
|
|
103
|
+
examples: examples$4,
|
|
104
104
|
schema: {
|
|
105
105
|
input: {
|
|
106
106
|
oneOf: [
|
|
@@ -218,14 +218,14 @@ function createCatalogRegisterAction(options) {
|
|
|
218
218
|
});
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
-
const id$
|
|
222
|
-
const examples$
|
|
221
|
+
const id$3 = "catalog:write";
|
|
222
|
+
const examples$3 = [
|
|
223
223
|
{
|
|
224
224
|
description: "Write a catalog yaml file",
|
|
225
225
|
example: yaml__namespace.stringify({
|
|
226
226
|
steps: [
|
|
227
227
|
{
|
|
228
|
-
action: id$
|
|
228
|
+
action: id$3,
|
|
229
229
|
id: "create-catalog-info-file",
|
|
230
230
|
name: "Create catalog file",
|
|
231
231
|
input: {
|
|
@@ -250,7 +250,7 @@ const examples$2 = [
|
|
|
250
250
|
];
|
|
251
251
|
function createCatalogWriteAction() {
|
|
252
252
|
return pluginScaffolderNode.createTemplateAction({
|
|
253
|
-
id: id$
|
|
253
|
+
id: id$3,
|
|
254
254
|
description: "Writes the catalog-info.yaml for your template",
|
|
255
255
|
schema: {
|
|
256
256
|
input: zod.z.object({
|
|
@@ -261,7 +261,7 @@ function createCatalogWriteAction() {
|
|
|
261
261
|
)
|
|
262
262
|
})
|
|
263
263
|
},
|
|
264
|
-
examples: examples$
|
|
264
|
+
examples: examples$3,
|
|
265
265
|
supportsDryRun: true,
|
|
266
266
|
async handler(ctx) {
|
|
267
267
|
ctx.logStream.write(`Writing catalog-info.yaml`);
|
|
@@ -275,14 +275,14 @@ function createCatalogWriteAction() {
|
|
|
275
275
|
});
|
|
276
276
|
}
|
|
277
277
|
|
|
278
|
-
const id$
|
|
279
|
-
const examples$
|
|
278
|
+
const id$2 = "catalog:fetch";
|
|
279
|
+
const examples$2 = [
|
|
280
280
|
{
|
|
281
281
|
description: "Fetch entity by reference",
|
|
282
282
|
example: yaml__default["default"].stringify({
|
|
283
283
|
steps: [
|
|
284
284
|
{
|
|
285
|
-
action: id$
|
|
285
|
+
action: id$2,
|
|
286
286
|
id: "fetch",
|
|
287
287
|
name: "Fetch catalog entity",
|
|
288
288
|
input: {
|
|
@@ -297,7 +297,7 @@ const examples$1 = [
|
|
|
297
297
|
example: yaml__default["default"].stringify({
|
|
298
298
|
steps: [
|
|
299
299
|
{
|
|
300
|
-
action: id$
|
|
300
|
+
action: id$2,
|
|
301
301
|
id: "fetchMultiple",
|
|
302
302
|
name: "Fetch catalog entities",
|
|
303
303
|
input: {
|
|
@@ -311,9 +311,9 @@ const examples$1 = [
|
|
|
311
311
|
function createFetchCatalogEntityAction(options) {
|
|
312
312
|
const { catalogClient } = options;
|
|
313
313
|
return pluginScaffolderNode.createTemplateAction({
|
|
314
|
-
id: id$
|
|
314
|
+
id: id$2,
|
|
315
315
|
description: "Returns entity or entities from the catalog by entity reference(s)",
|
|
316
|
-
examples: examples$
|
|
316
|
+
examples: examples$2,
|
|
317
317
|
schema: {
|
|
318
318
|
input: {
|
|
319
319
|
type: "object",
|
|
@@ -389,14 +389,14 @@ function createFetchCatalogEntityAction(options) {
|
|
|
389
389
|
});
|
|
390
390
|
}
|
|
391
391
|
|
|
392
|
-
const id = "debug:log";
|
|
393
|
-
const examples = [
|
|
392
|
+
const id$1 = "debug:log";
|
|
393
|
+
const examples$1 = [
|
|
394
394
|
{
|
|
395
395
|
description: "Write a debug message",
|
|
396
396
|
example: yaml__default["default"].stringify({
|
|
397
397
|
steps: [
|
|
398
398
|
{
|
|
399
|
-
action: id,
|
|
399
|
+
action: id$1,
|
|
400
400
|
id: "write-debug-line",
|
|
401
401
|
name: 'Write "Hello Backstage!" log line',
|
|
402
402
|
input: {
|
|
@@ -411,7 +411,7 @@ const examples = [
|
|
|
411
411
|
example: yaml__default["default"].stringify({
|
|
412
412
|
steps: [
|
|
413
413
|
{
|
|
414
|
-
action: id,
|
|
414
|
+
action: id$1,
|
|
415
415
|
id: "write-workspace-directory",
|
|
416
416
|
name: "List the workspace directory",
|
|
417
417
|
input: {
|
|
@@ -424,9 +424,9 @@ const examples = [
|
|
|
424
424
|
];
|
|
425
425
|
function createDebugLogAction() {
|
|
426
426
|
return pluginScaffolderNode.createTemplateAction({
|
|
427
|
-
id,
|
|
427
|
+
id: id$1,
|
|
428
428
|
description: "Writes a message into the log or lists all files in the workspace.",
|
|
429
|
-
examples,
|
|
429
|
+
examples: examples$1,
|
|
430
430
|
schema: {
|
|
431
431
|
input: {
|
|
432
432
|
type: "object",
|
|
@@ -473,6 +473,98 @@ async function recursiveReadDir(dir) {
|
|
|
473
473
|
return files.reduce((a, f) => a.concat(f), []);
|
|
474
474
|
}
|
|
475
475
|
|
|
476
|
+
const id = "debug:wait";
|
|
477
|
+
const MAX_WAIT_TIME_IN_ISO = "T00:00:30";
|
|
478
|
+
const examples = [
|
|
479
|
+
{
|
|
480
|
+
description: "Waiting for 5 seconds",
|
|
481
|
+
example: yaml__default["default"].stringify({
|
|
482
|
+
steps: [
|
|
483
|
+
{
|
|
484
|
+
action: id,
|
|
485
|
+
id: "wait-5sec",
|
|
486
|
+
name: "Waiting for 5 seconds",
|
|
487
|
+
input: {
|
|
488
|
+
seconds: 5
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
]
|
|
492
|
+
})
|
|
493
|
+
},
|
|
494
|
+
{
|
|
495
|
+
description: "Waiting for 5 minutes",
|
|
496
|
+
example: yaml__default["default"].stringify({
|
|
497
|
+
steps: [
|
|
498
|
+
{
|
|
499
|
+
action: id,
|
|
500
|
+
id: "wait-5min",
|
|
501
|
+
name: "Waiting for 5 minutes",
|
|
502
|
+
input: {
|
|
503
|
+
minutes: 5
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
]
|
|
507
|
+
})
|
|
508
|
+
}
|
|
509
|
+
];
|
|
510
|
+
function createWaitAction(options) {
|
|
511
|
+
const toDuration = (maxWaitTime) => {
|
|
512
|
+
if (maxWaitTime) {
|
|
513
|
+
if (maxWaitTime instanceof luxon.Duration) {
|
|
514
|
+
return maxWaitTime;
|
|
515
|
+
}
|
|
516
|
+
return luxon.Duration.fromObject(maxWaitTime);
|
|
517
|
+
}
|
|
518
|
+
return luxon.Duration.fromISOTime(MAX_WAIT_TIME_IN_ISO);
|
|
519
|
+
};
|
|
520
|
+
return pluginScaffolderNode.createTemplateAction({
|
|
521
|
+
id,
|
|
522
|
+
description: "Waits for a certain period of time.",
|
|
523
|
+
examples,
|
|
524
|
+
schema: {
|
|
525
|
+
input: {
|
|
526
|
+
type: "object",
|
|
527
|
+
properties: {
|
|
528
|
+
minutes: {
|
|
529
|
+
title: "Waiting period in minutes.",
|
|
530
|
+
type: "number"
|
|
531
|
+
},
|
|
532
|
+
seconds: {
|
|
533
|
+
title: "Waiting period in seconds.",
|
|
534
|
+
type: "number"
|
|
535
|
+
},
|
|
536
|
+
milliseconds: {
|
|
537
|
+
title: "Waiting period in milliseconds.",
|
|
538
|
+
type: "number"
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
},
|
|
543
|
+
async handler(ctx) {
|
|
544
|
+
const delayTime = luxon.Duration.fromObject(ctx.input);
|
|
545
|
+
const maxWait = toDuration(options == null ? void 0 : options.maxWaitTime);
|
|
546
|
+
if (delayTime.minus(maxWait).toMillis() > 0) {
|
|
547
|
+
throw new Error(
|
|
548
|
+
`Waiting duration is longer than the maximum threshold of ${maxWait.toHuman()}`
|
|
549
|
+
);
|
|
550
|
+
}
|
|
551
|
+
await new Promise((resolve) => {
|
|
552
|
+
var _a;
|
|
553
|
+
const controller = new AbortController();
|
|
554
|
+
const timeoutHandle = setTimeout(abort, delayTime.toMillis());
|
|
555
|
+
(_a = ctx.signal) == null ? void 0 : _a.addEventListener("abort", abort);
|
|
556
|
+
function abort() {
|
|
557
|
+
var _a2;
|
|
558
|
+
(_a2 = ctx.signal) == null ? void 0 : _a2.removeEventListener("abort", abort);
|
|
559
|
+
clearTimeout(timeoutHandle);
|
|
560
|
+
controller.abort();
|
|
561
|
+
resolve("finished");
|
|
562
|
+
}
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
|
|
476
568
|
async function fetchContents(options) {
|
|
477
569
|
const { reader, integrations, baseUrl, fetchUrl = ".", outputPath } = options;
|
|
478
570
|
let fetchUrlIsAbsolute = false;
|
|
@@ -3969,7 +4061,7 @@ const createPublishGitlabMergeRequestAction = (options) => {
|
|
|
3969
4061
|
title: "Gitlab Project path",
|
|
3970
4062
|
type: "string"
|
|
3971
4063
|
},
|
|
3972
|
-
|
|
4064
|
+
mergeRequestUrl: {
|
|
3973
4065
|
title: "MergeRequest(MR) URL",
|
|
3974
4066
|
type: "string",
|
|
3975
4067
|
description: "Link to the merge request in GitLab"
|
|
@@ -4141,6 +4233,7 @@ const createBuiltinActions = (options) => {
|
|
|
4141
4233
|
config
|
|
4142
4234
|
}),
|
|
4143
4235
|
createDebugLogAction(),
|
|
4236
|
+
createWaitAction(),
|
|
4144
4237
|
createCatalogRegisterAction({ catalogClient, integrations }),
|
|
4145
4238
|
createFetchCatalogEntityAction({ catalogClient }),
|
|
4146
4239
|
createCatalogWriteAction(),
|
|
@@ -4307,7 +4400,7 @@ class DatabaseTaskStore {
|
|
|
4307
4400
|
const updateCount = await tx("tasks").where({ id: task.id, status: "open" }).update({
|
|
4308
4401
|
status: "processing",
|
|
4309
4402
|
last_heartbeat_at: this.db.fn.now(),
|
|
4310
|
-
// remove the secrets when moving
|
|
4403
|
+
// remove the secrets when moving to processing state.
|
|
4311
4404
|
secrets: null
|
|
4312
4405
|
});
|
|
4313
4406
|
if (updateCount < 1) {
|
|
@@ -4355,7 +4448,7 @@ class DatabaseTaskStore {
|
|
|
4355
4448
|
async completeTask(options) {
|
|
4356
4449
|
const { taskId, status, eventBody } = options;
|
|
4357
4450
|
let oldStatus;
|
|
4358
|
-
if (
|
|
4451
|
+
if (["failed", "completed", "cancelled"].includes(status)) {
|
|
4359
4452
|
oldStatus = "processing";
|
|
4360
4453
|
} else {
|
|
4361
4454
|
throw new Error(
|
|
@@ -4366,6 +4459,30 @@ class DatabaseTaskStore {
|
|
|
4366
4459
|
const [task] = await tx("tasks").where({
|
|
4367
4460
|
id: taskId
|
|
4368
4461
|
}).limit(1).select();
|
|
4462
|
+
const updateTask = async (criteria) => {
|
|
4463
|
+
const updateCount = await tx("tasks").where(criteria).update({
|
|
4464
|
+
status
|
|
4465
|
+
});
|
|
4466
|
+
if (updateCount !== 1) {
|
|
4467
|
+
throw new errors.ConflictError(
|
|
4468
|
+
`Failed to update status to '${status}' for taskId ${taskId}`
|
|
4469
|
+
);
|
|
4470
|
+
}
|
|
4471
|
+
await tx("task_events").insert({
|
|
4472
|
+
task_id: taskId,
|
|
4473
|
+
event_type: "completion",
|
|
4474
|
+
body: JSON.stringify(eventBody)
|
|
4475
|
+
});
|
|
4476
|
+
};
|
|
4477
|
+
if (status === "cancelled") {
|
|
4478
|
+
await updateTask({
|
|
4479
|
+
id: taskId
|
|
4480
|
+
});
|
|
4481
|
+
return;
|
|
4482
|
+
}
|
|
4483
|
+
if (task.status === "cancelled") {
|
|
4484
|
+
return;
|
|
4485
|
+
}
|
|
4369
4486
|
if (!task) {
|
|
4370
4487
|
throw new Error(`No task with taskId ${taskId} found`);
|
|
4371
4488
|
}
|
|
@@ -4374,21 +4491,9 @@ class DatabaseTaskStore {
|
|
|
4374
4491
|
`Refusing to update status of run '${taskId}' to status '${status}' as it is currently '${task.status}', expected '${oldStatus}'`
|
|
4375
4492
|
);
|
|
4376
4493
|
}
|
|
4377
|
-
|
|
4494
|
+
await updateTask({
|
|
4378
4495
|
id: taskId,
|
|
4379
4496
|
status: oldStatus
|
|
4380
|
-
}).update({
|
|
4381
|
-
status
|
|
4382
|
-
});
|
|
4383
|
-
if (updateCount !== 1) {
|
|
4384
|
-
throw new errors.ConflictError(
|
|
4385
|
-
`Failed to update status to '${status}' for taskId ${taskId}`
|
|
4386
|
-
);
|
|
4387
|
-
}
|
|
4388
|
-
await tx("task_events").insert({
|
|
4389
|
-
task_id: taskId,
|
|
4390
|
-
event_type: "completion",
|
|
4391
|
-
body: JSON.stringify(eventBody)
|
|
4392
4497
|
});
|
|
4393
4498
|
});
|
|
4394
4499
|
}
|
|
@@ -4456,24 +4561,37 @@ class DatabaseTaskStore {
|
|
|
4456
4561
|
}
|
|
4457
4562
|
});
|
|
4458
4563
|
}
|
|
4564
|
+
async cancelTask(options) {
|
|
4565
|
+
const { taskId, body } = options;
|
|
4566
|
+
const serializedBody = JSON.stringify(body);
|
|
4567
|
+
await this.db("task_events").insert({
|
|
4568
|
+
task_id: taskId,
|
|
4569
|
+
event_type: "cancelled",
|
|
4570
|
+
body: serializedBody
|
|
4571
|
+
});
|
|
4572
|
+
}
|
|
4459
4573
|
}
|
|
4460
4574
|
|
|
4461
4575
|
class TaskManager {
|
|
4462
4576
|
// Runs heartbeat internally
|
|
4463
|
-
constructor(task, storage, logger) {
|
|
4577
|
+
constructor(task, storage, signal, logger) {
|
|
4464
4578
|
this.task = task;
|
|
4465
4579
|
this.storage = storage;
|
|
4580
|
+
this.signal = signal;
|
|
4466
4581
|
this.logger = logger;
|
|
4467
4582
|
this.isDone = false;
|
|
4468
4583
|
}
|
|
4469
|
-
static create(task, storage, logger) {
|
|
4470
|
-
const agent = new TaskManager(task, storage, logger);
|
|
4584
|
+
static create(task, storage, abortSignal, logger) {
|
|
4585
|
+
const agent = new TaskManager(task, storage, abortSignal, logger);
|
|
4471
4586
|
agent.startTimeout();
|
|
4472
4587
|
return agent;
|
|
4473
4588
|
}
|
|
4474
4589
|
get spec() {
|
|
4475
4590
|
return this.task.spec;
|
|
4476
4591
|
}
|
|
4592
|
+
get cancelSignal() {
|
|
4593
|
+
return this.signal;
|
|
4594
|
+
}
|
|
4477
4595
|
get secrets() {
|
|
4478
4596
|
return this.task.secrets;
|
|
4479
4597
|
}
|
|
@@ -4543,6 +4661,28 @@ class StorageTaskBroker {
|
|
|
4543
4661
|
}
|
|
4544
4662
|
return await this.storage.list({ createdBy: options == null ? void 0 : options.createdBy });
|
|
4545
4663
|
}
|
|
4664
|
+
async registerCancellable(taskId, abortController) {
|
|
4665
|
+
let shouldUnsubscribe = false;
|
|
4666
|
+
const subscription = this.event$({ taskId, after: void 0 }).subscribe({
|
|
4667
|
+
error: (_) => {
|
|
4668
|
+
subscription.unsubscribe();
|
|
4669
|
+
},
|
|
4670
|
+
next: ({ events }) => {
|
|
4671
|
+
for (const event of events) {
|
|
4672
|
+
if (event.type === "cancelled") {
|
|
4673
|
+
abortController.abort();
|
|
4674
|
+
shouldUnsubscribe = true;
|
|
4675
|
+
}
|
|
4676
|
+
if (event.type === "completion") {
|
|
4677
|
+
shouldUnsubscribe = true;
|
|
4678
|
+
}
|
|
4679
|
+
}
|
|
4680
|
+
if (shouldUnsubscribe) {
|
|
4681
|
+
subscription.unsubscribe();
|
|
4682
|
+
}
|
|
4683
|
+
}
|
|
4684
|
+
});
|
|
4685
|
+
}
|
|
4546
4686
|
/**
|
|
4547
4687
|
* {@inheritdoc TaskBroker.claim}
|
|
4548
4688
|
*/
|
|
@@ -4550,6 +4690,8 @@ class StorageTaskBroker {
|
|
|
4550
4690
|
for (; ; ) {
|
|
4551
4691
|
const pendingTask = await this.storage.claimTask();
|
|
4552
4692
|
if (pendingTask) {
|
|
4693
|
+
const abortController = new AbortController();
|
|
4694
|
+
await this.registerCancellable(pendingTask.id, abortController);
|
|
4553
4695
|
return TaskManager.create(
|
|
4554
4696
|
{
|
|
4555
4697
|
taskId: pendingTask.id,
|
|
@@ -4558,6 +4700,7 @@ class StorageTaskBroker {
|
|
|
4558
4700
|
createdBy: pendingTask.createdBy
|
|
4559
4701
|
},
|
|
4560
4702
|
this.storage,
|
|
4703
|
+
abortController.signal,
|
|
4561
4704
|
this.logger
|
|
4562
4705
|
);
|
|
4563
4706
|
}
|
|
@@ -4632,6 +4775,19 @@ class StorageTaskBroker {
|
|
|
4632
4775
|
this.deferredDispatch.resolve();
|
|
4633
4776
|
this.deferredDispatch = defer();
|
|
4634
4777
|
}
|
|
4778
|
+
async cancel(taskId) {
|
|
4779
|
+
var _a, _b;
|
|
4780
|
+
const { events } = await this.storage.listEvents({ taskId });
|
|
4781
|
+
const currentStepId = events.length > 0 ? events.filter(({ body }) => body == null ? void 0 : body.stepId).reduce((prev, curr) => prev.id > curr.id ? prev : curr).body.stepId : 0;
|
|
4782
|
+
await ((_b = (_a = this.storage).cancelTask) == null ? void 0 : _b.call(_a, {
|
|
4783
|
+
taskId,
|
|
4784
|
+
body: {
|
|
4785
|
+
message: `Step ${currentStepId} has been cancelled.`,
|
|
4786
|
+
stepId: currentStepId,
|
|
4787
|
+
status: "cancelled"
|
|
4788
|
+
}
|
|
4789
|
+
}));
|
|
4790
|
+
}
|
|
4635
4791
|
}
|
|
4636
4792
|
|
|
4637
4793
|
function isTruthy(value) {
|
|
@@ -4763,8 +4919,107 @@ class NunjucksWorkflowRunner {
|
|
|
4763
4919
|
return value;
|
|
4764
4920
|
});
|
|
4765
4921
|
}
|
|
4766
|
-
async
|
|
4922
|
+
async executeStep(task, step, context, renderTemplate, taskTrack, workspacePath) {
|
|
4767
4923
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
4924
|
+
const stepTrack = await this.tracker.stepStart(task, step);
|
|
4925
|
+
if (task.cancelSignal.aborted) {
|
|
4926
|
+
throw new Error(`Step ${step.name} has been cancelled.`);
|
|
4927
|
+
}
|
|
4928
|
+
try {
|
|
4929
|
+
if (step.if) {
|
|
4930
|
+
const ifResult = await this.render(step.if, context, renderTemplate);
|
|
4931
|
+
if (!isTruthy(ifResult)) {
|
|
4932
|
+
await stepTrack.skipFalsy();
|
|
4933
|
+
return;
|
|
4934
|
+
}
|
|
4935
|
+
}
|
|
4936
|
+
const action = this.options.actionRegistry.get(step.action);
|
|
4937
|
+
const { taskLogger, streamLogger } = createStepLogger({ task, step });
|
|
4938
|
+
if (task.isDryRun) {
|
|
4939
|
+
const redactedSecrets = Object.fromEntries(
|
|
4940
|
+
Object.entries((_a = task.secrets) != null ? _a : {}).map((secret) => [
|
|
4941
|
+
secret[0],
|
|
4942
|
+
"[REDACTED]"
|
|
4943
|
+
])
|
|
4944
|
+
);
|
|
4945
|
+
const debugInput = (_b = step.input && this.render(
|
|
4946
|
+
step.input,
|
|
4947
|
+
{
|
|
4948
|
+
...context,
|
|
4949
|
+
secrets: redactedSecrets
|
|
4950
|
+
},
|
|
4951
|
+
renderTemplate
|
|
4952
|
+
)) != null ? _b : {};
|
|
4953
|
+
taskLogger.info(
|
|
4954
|
+
`Running ${action.id} in dry-run mode with inputs (secrets redacted): ${JSON.stringify(
|
|
4955
|
+
debugInput,
|
|
4956
|
+
void 0,
|
|
4957
|
+
2
|
|
4958
|
+
)}`
|
|
4959
|
+
);
|
|
4960
|
+
if (!action.supportsDryRun) {
|
|
4961
|
+
await taskTrack.skipDryRun(step, action);
|
|
4962
|
+
const outputSchema = (_c = action.schema) == null ? void 0 : _c.output;
|
|
4963
|
+
if (outputSchema) {
|
|
4964
|
+
context.steps[step.id] = {
|
|
4965
|
+
output: generateExampleOutput(outputSchema)
|
|
4966
|
+
};
|
|
4967
|
+
} else {
|
|
4968
|
+
context.steps[step.id] = { output: {} };
|
|
4969
|
+
}
|
|
4970
|
+
return;
|
|
4971
|
+
}
|
|
4972
|
+
}
|
|
4973
|
+
const input = (_e = step.input && this.render(
|
|
4974
|
+
step.input,
|
|
4975
|
+
{ ...context, secrets: (_d = task.secrets) != null ? _d : {} },
|
|
4976
|
+
renderTemplate
|
|
4977
|
+
)) != null ? _e : {};
|
|
4978
|
+
if ((_f = action.schema) == null ? void 0 : _f.input) {
|
|
4979
|
+
const validateResult = jsonschema.validate(input, action.schema.input);
|
|
4980
|
+
if (!validateResult.valid) {
|
|
4981
|
+
const errors$1 = validateResult.errors.join(", ");
|
|
4982
|
+
throw new errors.InputError(
|
|
4983
|
+
`Invalid input passed to action ${action.id}, ${errors$1}`
|
|
4984
|
+
);
|
|
4985
|
+
}
|
|
4986
|
+
}
|
|
4987
|
+
const tmpDirs = new Array();
|
|
4988
|
+
const stepOutput = {};
|
|
4989
|
+
await action.handler({
|
|
4990
|
+
input,
|
|
4991
|
+
secrets: (_g = task.secrets) != null ? _g : {},
|
|
4992
|
+
logger: taskLogger,
|
|
4993
|
+
logStream: streamLogger,
|
|
4994
|
+
workspacePath,
|
|
4995
|
+
createTemporaryDirectory: async () => {
|
|
4996
|
+
const tmpDir = await fs__default["default"].mkdtemp(`${workspacePath}_step-${step.id}-`);
|
|
4997
|
+
tmpDirs.push(tmpDir);
|
|
4998
|
+
return tmpDir;
|
|
4999
|
+
},
|
|
5000
|
+
output(name, value) {
|
|
5001
|
+
stepOutput[name] = value;
|
|
5002
|
+
},
|
|
5003
|
+
templateInfo: task.spec.templateInfo,
|
|
5004
|
+
user: task.spec.user,
|
|
5005
|
+
isDryRun: task.isDryRun,
|
|
5006
|
+
signal: task.cancelSignal
|
|
5007
|
+
});
|
|
5008
|
+
for (const tmpDir of tmpDirs) {
|
|
5009
|
+
await fs__default["default"].remove(tmpDir);
|
|
5010
|
+
}
|
|
5011
|
+
context.steps[step.id] = { output: stepOutput };
|
|
5012
|
+
if (task.cancelSignal.aborted) {
|
|
5013
|
+
throw new Error(`Step ${step.name} has been cancelled.`);
|
|
5014
|
+
}
|
|
5015
|
+
await stepTrack.markSuccessful();
|
|
5016
|
+
} catch (err) {
|
|
5017
|
+
await taskTrack.markFailed(step, err);
|
|
5018
|
+
await stepTrack.markFailed();
|
|
5019
|
+
throw err;
|
|
5020
|
+
}
|
|
5021
|
+
}
|
|
5022
|
+
async execute(task) {
|
|
4768
5023
|
if (!isValidTaskSpec(task.spec)) {
|
|
4769
5024
|
throw new errors.InputError(
|
|
4770
5025
|
"Wrong template version executed with the workflow engine"
|
|
@@ -4774,7 +5029,11 @@ class NunjucksWorkflowRunner {
|
|
|
4774
5029
|
this.options.workingDirectory,
|
|
4775
5030
|
await task.getWorkspaceName()
|
|
4776
5031
|
);
|
|
4777
|
-
const {
|
|
5032
|
+
const {
|
|
5033
|
+
additionalTemplateFilters,
|
|
5034
|
+
additionalTemplateGlobals,
|
|
5035
|
+
integrations
|
|
5036
|
+
} = this.options;
|
|
4778
5037
|
const renderTemplate = await SecureTemplater.loadRenderer({
|
|
4779
5038
|
// TODO(blam): let's work out how we can deprecate this.
|
|
4780
5039
|
// We shouldn't really need to be exposing these now we can deal with
|
|
@@ -4783,8 +5042,8 @@ class NunjucksWorkflowRunner {
|
|
|
4783
5042
|
parseRepoUrl(url) {
|
|
4784
5043
|
return parseRepoUrl(url, integrations);
|
|
4785
5044
|
},
|
|
4786
|
-
additionalTemplateFilters
|
|
4787
|
-
additionalTemplateGlobals
|
|
5045
|
+
additionalTemplateFilters,
|
|
5046
|
+
additionalTemplateGlobals
|
|
4788
5047
|
});
|
|
4789
5048
|
try {
|
|
4790
5049
|
const taskTrack = await this.tracker.taskStart(task);
|
|
@@ -4795,105 +5054,14 @@ class NunjucksWorkflowRunner {
|
|
|
4795
5054
|
user: task.spec.user
|
|
4796
5055
|
};
|
|
4797
5056
|
for (const step of task.spec.steps) {
|
|
4798
|
-
|
|
4799
|
-
|
|
4800
|
-
|
|
4801
|
-
|
|
4802
|
-
|
|
4803
|
-
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
if (!isTruthy(ifResult)) {
|
|
4807
|
-
await stepTrack.skipFalsy();
|
|
4808
|
-
continue;
|
|
4809
|
-
}
|
|
4810
|
-
}
|
|
4811
|
-
const action = this.options.actionRegistry.get(step.action);
|
|
4812
|
-
const { taskLogger, streamLogger } = createStepLogger({ task, step });
|
|
4813
|
-
if (task.isDryRun) {
|
|
4814
|
-
const redactedSecrets = Object.fromEntries(
|
|
4815
|
-
Object.entries((_a = task.secrets) != null ? _a : {}).map((secret) => [
|
|
4816
|
-
secret[0],
|
|
4817
|
-
"[REDACTED]"
|
|
4818
|
-
])
|
|
4819
|
-
);
|
|
4820
|
-
const debugInput = (_b = step.input && this.render(
|
|
4821
|
-
step.input,
|
|
4822
|
-
{
|
|
4823
|
-
...context,
|
|
4824
|
-
secrets: redactedSecrets
|
|
4825
|
-
},
|
|
4826
|
-
renderTemplate
|
|
4827
|
-
)) != null ? _b : {};
|
|
4828
|
-
taskLogger.info(
|
|
4829
|
-
`Running ${action.id} in dry-run mode with inputs (secrets redacted): ${JSON.stringify(
|
|
4830
|
-
debugInput,
|
|
4831
|
-
void 0,
|
|
4832
|
-
2
|
|
4833
|
-
)}`
|
|
4834
|
-
);
|
|
4835
|
-
if (!action.supportsDryRun) {
|
|
4836
|
-
await taskTrack.skipDryRun(step, action);
|
|
4837
|
-
const outputSchema = (_c = action.schema) == null ? void 0 : _c.output;
|
|
4838
|
-
if (outputSchema) {
|
|
4839
|
-
context.steps[step.id] = {
|
|
4840
|
-
output: generateExampleOutput(outputSchema)
|
|
4841
|
-
};
|
|
4842
|
-
} else {
|
|
4843
|
-
context.steps[step.id] = { output: {} };
|
|
4844
|
-
}
|
|
4845
|
-
continue;
|
|
4846
|
-
}
|
|
4847
|
-
}
|
|
4848
|
-
const input = (_e = step.input && this.render(
|
|
4849
|
-
step.input,
|
|
4850
|
-
{ ...context, secrets: (_d = task.secrets) != null ? _d : {} },
|
|
4851
|
-
renderTemplate
|
|
4852
|
-
)) != null ? _e : {};
|
|
4853
|
-
if ((_f = action.schema) == null ? void 0 : _f.input) {
|
|
4854
|
-
const validateResult = jsonschema.validate(
|
|
4855
|
-
input,
|
|
4856
|
-
action.schema.input
|
|
4857
|
-
);
|
|
4858
|
-
if (!validateResult.valid) {
|
|
4859
|
-
const errors$1 = validateResult.errors.join(", ");
|
|
4860
|
-
throw new errors.InputError(
|
|
4861
|
-
`Invalid input passed to action ${action.id}, ${errors$1}`
|
|
4862
|
-
);
|
|
4863
|
-
}
|
|
4864
|
-
}
|
|
4865
|
-
const tmpDirs = new Array();
|
|
4866
|
-
const stepOutput = {};
|
|
4867
|
-
await action.handler({
|
|
4868
|
-
input,
|
|
4869
|
-
secrets: (_g = task.secrets) != null ? _g : {},
|
|
4870
|
-
logger: taskLogger,
|
|
4871
|
-
logStream: streamLogger,
|
|
4872
|
-
workspacePath,
|
|
4873
|
-
createTemporaryDirectory: async () => {
|
|
4874
|
-
const tmpDir = await fs__default["default"].mkdtemp(
|
|
4875
|
-
`${workspacePath}_step-${step.id}-`
|
|
4876
|
-
);
|
|
4877
|
-
tmpDirs.push(tmpDir);
|
|
4878
|
-
return tmpDir;
|
|
4879
|
-
},
|
|
4880
|
-
output(name, value) {
|
|
4881
|
-
stepOutput[name] = value;
|
|
4882
|
-
},
|
|
4883
|
-
templateInfo: task.spec.templateInfo,
|
|
4884
|
-
user: task.spec.user,
|
|
4885
|
-
isDryRun: task.isDryRun
|
|
4886
|
-
});
|
|
4887
|
-
for (const tmpDir of tmpDirs) {
|
|
4888
|
-
await fs__default["default"].remove(tmpDir);
|
|
4889
|
-
}
|
|
4890
|
-
context.steps[step.id] = { output: stepOutput };
|
|
4891
|
-
await stepTrack.markSuccessful();
|
|
4892
|
-
} catch (err) {
|
|
4893
|
-
await taskTrack.markFailed(step, err);
|
|
4894
|
-
await stepTrack.markFailed();
|
|
4895
|
-
throw err;
|
|
4896
|
-
}
|
|
5057
|
+
await this.executeStep(
|
|
5058
|
+
task,
|
|
5059
|
+
step,
|
|
5060
|
+
context,
|
|
5061
|
+
renderTemplate,
|
|
5062
|
+
taskTrack,
|
|
5063
|
+
workspacePath
|
|
5064
|
+
);
|
|
4897
5065
|
}
|
|
4898
5066
|
const output = this.render(task.spec.output, context, renderTemplate);
|
|
4899
5067
|
await taskTrack.markSuccessful();
|
|
@@ -4960,8 +5128,21 @@ function scaffoldingTracker() {
|
|
|
4960
5128
|
});
|
|
4961
5129
|
taskTimer({ result: "failed" });
|
|
4962
5130
|
}
|
|
5131
|
+
async function markCancelled(step) {
|
|
5132
|
+
await task.emitLog(`Step ${step.id} has been cancelled.`, {
|
|
5133
|
+
stepId: step.id,
|
|
5134
|
+
status: "cancelled"
|
|
5135
|
+
});
|
|
5136
|
+
taskCount.inc({
|
|
5137
|
+
template,
|
|
5138
|
+
user,
|
|
5139
|
+
result: "cancelled"
|
|
5140
|
+
});
|
|
5141
|
+
taskTimer({ result: "cancelled" });
|
|
5142
|
+
}
|
|
4963
5143
|
return {
|
|
4964
5144
|
skipDryRun,
|
|
5145
|
+
markCancelled,
|
|
4965
5146
|
markSuccessful,
|
|
4966
5147
|
markFailed
|
|
4967
5148
|
};
|
|
@@ -4989,6 +5170,14 @@ function scaffoldingTracker() {
|
|
|
4989
5170
|
});
|
|
4990
5171
|
stepTimer({ result: "ok" });
|
|
4991
5172
|
}
|
|
5173
|
+
async function markCancelled() {
|
|
5174
|
+
stepCount.inc({
|
|
5175
|
+
template,
|
|
5176
|
+
step: step.name,
|
|
5177
|
+
result: "cancelled"
|
|
5178
|
+
});
|
|
5179
|
+
stepTimer({ result: "cancelled" });
|
|
5180
|
+
}
|
|
4992
5181
|
async function markFailed() {
|
|
4993
5182
|
stepCount.inc({
|
|
4994
5183
|
template,
|
|
@@ -5005,8 +5194,9 @@ function scaffoldingTracker() {
|
|
|
5005
5194
|
stepTimer({ result: "skipped" });
|
|
5006
5195
|
}
|
|
5007
5196
|
return {
|
|
5008
|
-
|
|
5197
|
+
markCancelled,
|
|
5009
5198
|
markFailed,
|
|
5199
|
+
markSuccessful,
|
|
5010
5200
|
skipFalsy
|
|
5011
5201
|
};
|
|
5012
5202
|
}
|
|
@@ -5130,6 +5320,7 @@ function createDryRunner(options) {
|
|
|
5130
5320
|
);
|
|
5131
5321
|
try {
|
|
5132
5322
|
await deserializeDirectoryContents(contentsPath, input.directoryContents);
|
|
5323
|
+
const abortSignal = new AbortController().signal;
|
|
5133
5324
|
const result = await workflowRunner.execute({
|
|
5134
5325
|
spec: {
|
|
5135
5326
|
...input.spec,
|
|
@@ -5153,6 +5344,7 @@ function createDryRunner(options) {
|
|
|
5153
5344
|
done: false,
|
|
5154
5345
|
isDryRun: true,
|
|
5155
5346
|
getWorkspaceName: async () => `dry-run-${dryRunId}`,
|
|
5347
|
+
cancelSignal: abortSignal,
|
|
5156
5348
|
async emitLog(message, logMetadata) {
|
|
5157
5349
|
if ((logMetadata == null ? void 0 : logMetadata.stepId) === dryRunId) {
|
|
5158
5350
|
return;
|
|
@@ -5164,7 +5356,7 @@ function createDryRunner(options) {
|
|
|
5164
5356
|
}
|
|
5165
5357
|
});
|
|
5166
5358
|
},
|
|
5167
|
-
async
|
|
5359
|
+
complete: async () => {
|
|
5168
5360
|
throw new Error("Not implemented");
|
|
5169
5361
|
}
|
|
5170
5362
|
});
|
|
@@ -5495,6 +5687,11 @@ async function createRouter(options) {
|
|
|
5495
5687
|
}
|
|
5496
5688
|
delete task.secrets;
|
|
5497
5689
|
res.status(200).json(task);
|
|
5690
|
+
}).post("/v2/tasks/:taskId/cancel", async (req, res) => {
|
|
5691
|
+
var _a;
|
|
5692
|
+
const { taskId } = req.params;
|
|
5693
|
+
await ((_a = taskBroker.cancel) == null ? void 0 : _a.call(taskBroker, taskId));
|
|
5694
|
+
res.status(200).json({ status: "cancelled" });
|
|
5498
5695
|
}).get("/v2/tasks/:taskId/eventstream", async (req, res) => {
|
|
5499
5696
|
const { taskId } = req.params;
|
|
5500
5697
|
const after = req.query.after !== void 0 ? Number(req.query.after) : void 0;
|
|
@@ -5651,7 +5848,7 @@ class ScaffolderEntitiesProcessor {
|
|
|
5651
5848
|
defaultNamespace: selfRef.namespace
|
|
5652
5849
|
});
|
|
5653
5850
|
emit(
|
|
5654
|
-
|
|
5851
|
+
pluginCatalogNode.processingResult.relation({
|
|
5655
5852
|
source: selfRef,
|
|
5656
5853
|
type: catalogModel.RELATION_OWNED_BY,
|
|
5657
5854
|
target: {
|
|
@@ -5662,7 +5859,7 @@ class ScaffolderEntitiesProcessor {
|
|
|
5662
5859
|
})
|
|
5663
5860
|
);
|
|
5664
5861
|
emit(
|
|
5665
|
-
|
|
5862
|
+
pluginCatalogNode.processingResult.relation({
|
|
5666
5863
|
source: {
|
|
5667
5864
|
kind: targetRef.kind,
|
|
5668
5865
|
namespace: targetRef.namespace,
|
|
@@ -5711,6 +5908,7 @@ exports.createPublishGitlabAction = createPublishGitlabAction;
|
|
|
5711
5908
|
exports.createPublishGitlabMergeRequestAction = createPublishGitlabMergeRequestAction;
|
|
5712
5909
|
exports.createRouter = createRouter;
|
|
5713
5910
|
exports.createTemplateAction = createTemplateAction;
|
|
5911
|
+
exports.createWaitAction = createWaitAction;
|
|
5714
5912
|
exports.executeShellCommand = executeShellCommand;
|
|
5715
5913
|
exports.fetchContents = fetchContents;
|
|
5716
5914
|
//# sourceMappingURL=index.cjs.js.map
|