@backstage/plugin-scaffolder-backend 1.7.0 → 1.8.0-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 +57 -0
- package/alpha/package.json +1 -1
- package/dist/index.cjs.js +137 -26
- package/dist/index.cjs.js.map +1 -1
- package/package.json +17 -16
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,62 @@
|
|
|
1
1
|
# @backstage/plugin-scaffolder-backend
|
|
2
2
|
|
|
3
|
+
## 1.8.0-next.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- ea14eb62a2: Added a set of default Prometheus metrics around scaffolding. See below for a list of metrics and an explanation of their labels:
|
|
8
|
+
|
|
9
|
+
- `scaffolder_task_count`: Tracks successful task runs.
|
|
10
|
+
|
|
11
|
+
Labels:
|
|
12
|
+
|
|
13
|
+
- `template`: The entity ref of the scaffolded template
|
|
14
|
+
- `user`: The entity ref of the user that invoked the template run
|
|
15
|
+
- `result`: A string describing whether the task ran successfully, failed, or was skipped
|
|
16
|
+
|
|
17
|
+
- `scaffolder_task_duration`: a histogram which tracks the duration of a task run
|
|
18
|
+
|
|
19
|
+
Labels:
|
|
20
|
+
|
|
21
|
+
- `template`: The entity ref of the scaffolded template
|
|
22
|
+
- `result`: A boolean describing whether the task ran successfully
|
|
23
|
+
|
|
24
|
+
- `scaffolder_step_count`: a count that tracks each step run
|
|
25
|
+
|
|
26
|
+
Labels:
|
|
27
|
+
|
|
28
|
+
- `template`: The entity ref of the scaffolded template
|
|
29
|
+
- `step`: The name of the step that was run
|
|
30
|
+
- `result`: A string describing whether the task ran successfully, failed, or was skipped
|
|
31
|
+
|
|
32
|
+
- `scaffolder_step_duration`: a histogram which tracks the duration of each step run
|
|
33
|
+
|
|
34
|
+
Labels:
|
|
35
|
+
|
|
36
|
+
- `template`: The entity ref of the scaffolded template
|
|
37
|
+
- `step`: The name of the step that was run
|
|
38
|
+
- `result`: A string describing whether the task ran successfully, failed, or was skipped
|
|
39
|
+
|
|
40
|
+
You can find a guide for running Prometheus metrics here: https://github.com/backstage/backstage/blob/master/contrib/docs/tutorials/prometheus-metrics.md
|
|
41
|
+
|
|
42
|
+
### Patch Changes
|
|
43
|
+
|
|
44
|
+
- 7573b65232: Internal refactor of imports to avoid circular dependencies
|
|
45
|
+
- Updated dependencies
|
|
46
|
+
- @backstage/backend-common@0.16.0-next.0
|
|
47
|
+
- @backstage/plugin-catalog-backend@1.5.1-next.0
|
|
48
|
+
- @backstage/integration@1.4.0-next.0
|
|
49
|
+
- @backstage/backend-tasks@0.3.7-next.0
|
|
50
|
+
- @backstage/catalog-model@1.1.3-next.0
|
|
51
|
+
- @backstage/plugin-auth-node@0.2.7-next.0
|
|
52
|
+
- @backstage/types@1.0.1-next.0
|
|
53
|
+
- @backstage/backend-plugin-api@0.1.4-next.0
|
|
54
|
+
- @backstage/plugin-catalog-node@1.2.1-next.0
|
|
55
|
+
- @backstage/catalog-client@1.1.2-next.0
|
|
56
|
+
- @backstage/config@1.0.4-next.0
|
|
57
|
+
- @backstage/errors@1.1.3-next.0
|
|
58
|
+
- @backstage/plugin-scaffolder-common@1.2.2-next.0
|
|
59
|
+
|
|
3
60
|
## 1.7.0
|
|
4
61
|
|
|
5
62
|
### Minor Changes
|
package/alpha/package.json
CHANGED
package/dist/index.cjs.js
CHANGED
|
@@ -30,6 +30,7 @@ var winston = require('winston');
|
|
|
30
30
|
var nunjucks = require('nunjucks');
|
|
31
31
|
var lodash = require('lodash');
|
|
32
32
|
var jsonschema = require('jsonschema');
|
|
33
|
+
var promClient = require('prom-client');
|
|
33
34
|
var pluginScaffolderCommon = require('@backstage/plugin-scaffolder-common');
|
|
34
35
|
var express = require('express');
|
|
35
36
|
var Router = require('express-promise-router');
|
|
@@ -4188,6 +4189,23 @@ function generateExampleOutput(schema) {
|
|
|
4188
4189
|
return "<unknown>";
|
|
4189
4190
|
}
|
|
4190
4191
|
|
|
4192
|
+
function createCounterMetric(config) {
|
|
4193
|
+
let metric = promClient.register.getSingleMetric(config.name);
|
|
4194
|
+
if (!metric) {
|
|
4195
|
+
metric = new promClient.Counter(config);
|
|
4196
|
+
promClient.register.registerMetric(metric);
|
|
4197
|
+
}
|
|
4198
|
+
return metric;
|
|
4199
|
+
}
|
|
4200
|
+
function createHistogramMetric(config) {
|
|
4201
|
+
let metric = promClient.register.getSingleMetric(config.name);
|
|
4202
|
+
if (!metric) {
|
|
4203
|
+
metric = new promClient.Histogram(config);
|
|
4204
|
+
promClient.register.registerMetric(metric);
|
|
4205
|
+
}
|
|
4206
|
+
return metric;
|
|
4207
|
+
}
|
|
4208
|
+
|
|
4191
4209
|
const isValidTaskSpec = (taskSpec) => {
|
|
4192
4210
|
return taskSpec.apiVersion === "scaffolder.backstage.io/v1beta3";
|
|
4193
4211
|
};
|
|
@@ -4217,6 +4235,7 @@ const createStepLogger = ({
|
|
|
4217
4235
|
class NunjucksWorkflowRunner {
|
|
4218
4236
|
constructor(options) {
|
|
4219
4237
|
this.options = options;
|
|
4238
|
+
this.tracker = scaffoldingTracker();
|
|
4220
4239
|
}
|
|
4221
4240
|
isSingleTemplateString(input) {
|
|
4222
4241
|
var _a, _b;
|
|
@@ -4287,16 +4306,15 @@ class NunjucksWorkflowRunner {
|
|
|
4287
4306
|
additionalTemplateGlobals: this.options.additionalTemplateGlobals
|
|
4288
4307
|
});
|
|
4289
4308
|
try {
|
|
4309
|
+
const taskTrack = await this.tracker.taskStart(task);
|
|
4290
4310
|
await fs__default["default"].ensureDir(workspacePath);
|
|
4291
|
-
await task.emitLog(
|
|
4292
|
-
`Starting up task with ${task.spec.steps.length} steps`
|
|
4293
|
-
);
|
|
4294
4311
|
const context = {
|
|
4295
4312
|
parameters: task.spec.parameters,
|
|
4296
4313
|
steps: {},
|
|
4297
4314
|
user: task.spec.user
|
|
4298
4315
|
};
|
|
4299
4316
|
for (const step of task.spec.steps) {
|
|
4317
|
+
const stepTrack = await this.tracker.stepStart(task, step);
|
|
4300
4318
|
try {
|
|
4301
4319
|
if (step.if) {
|
|
4302
4320
|
const ifResult = await this.render(
|
|
@@ -4305,17 +4323,10 @@ class NunjucksWorkflowRunner {
|
|
|
4305
4323
|
renderTemplate
|
|
4306
4324
|
);
|
|
4307
4325
|
if (!isTruthy(ifResult)) {
|
|
4308
|
-
await
|
|
4309
|
-
`Skipping step ${step.id} because it's if condition was false`,
|
|
4310
|
-
{ stepId: step.id, status: "skipped" }
|
|
4311
|
-
);
|
|
4326
|
+
await stepTrack.skipFalsy();
|
|
4312
4327
|
continue;
|
|
4313
4328
|
}
|
|
4314
4329
|
}
|
|
4315
|
-
await task.emitLog(`Beginning step ${step.name}`, {
|
|
4316
|
-
stepId: step.id,
|
|
4317
|
-
status: "processing"
|
|
4318
|
-
});
|
|
4319
4330
|
const action = this.options.actionRegistry.get(step.action);
|
|
4320
4331
|
const { taskLogger, streamLogger } = createStepLogger({ task, step });
|
|
4321
4332
|
if (task.isDryRun) {
|
|
@@ -4341,13 +4352,7 @@ class NunjucksWorkflowRunner {
|
|
|
4341
4352
|
)}`
|
|
4342
4353
|
);
|
|
4343
4354
|
if (!action.supportsDryRun) {
|
|
4344
|
-
|
|
4345
|
-
`Skipping because ${action.id} does not support dry-run`,
|
|
4346
|
-
{
|
|
4347
|
-
stepId: step.id,
|
|
4348
|
-
status: "skipped"
|
|
4349
|
-
}
|
|
4350
|
-
);
|
|
4355
|
+
await taskTrack.skipDryRun(step, action);
|
|
4351
4356
|
const outputSchema = (_c = action.schema) == null ? void 0 : _c.output;
|
|
4352
4357
|
if (outputSchema) {
|
|
4353
4358
|
context.steps[step.id] = {
|
|
@@ -4402,19 +4407,15 @@ class NunjucksWorkflowRunner {
|
|
|
4402
4407
|
await fs__default["default"].remove(tmpDir);
|
|
4403
4408
|
}
|
|
4404
4409
|
context.steps[step.id] = { output: stepOutput };
|
|
4405
|
-
await
|
|
4406
|
-
stepId: step.id,
|
|
4407
|
-
status: "completed"
|
|
4408
|
-
});
|
|
4410
|
+
await stepTrack.markSuccessful();
|
|
4409
4411
|
} catch (err) {
|
|
4410
|
-
await
|
|
4411
|
-
|
|
4412
|
-
status: "failed"
|
|
4413
|
-
});
|
|
4412
|
+
await taskTrack.markFailed(step, err);
|
|
4413
|
+
await stepTrack.markFailed();
|
|
4414
4414
|
throw err;
|
|
4415
4415
|
}
|
|
4416
4416
|
}
|
|
4417
4417
|
const output = this.render(task.spec.output, context, renderTemplate);
|
|
4418
|
+
await taskTrack.markSuccessful();
|
|
4418
4419
|
return { output };
|
|
4419
4420
|
} finally {
|
|
4420
4421
|
if (workspacePath) {
|
|
@@ -4423,6 +4424,116 @@ class NunjucksWorkflowRunner {
|
|
|
4423
4424
|
}
|
|
4424
4425
|
}
|
|
4425
4426
|
}
|
|
4427
|
+
function scaffoldingTracker() {
|
|
4428
|
+
const taskCount = createCounterMetric({
|
|
4429
|
+
name: "scaffolder_task_count",
|
|
4430
|
+
help: "Count of task runs",
|
|
4431
|
+
labelNames: ["template", "user", "result"]
|
|
4432
|
+
});
|
|
4433
|
+
const taskDuration = createHistogramMetric({
|
|
4434
|
+
name: "scaffolder_task_duration",
|
|
4435
|
+
help: "Duration of a task run",
|
|
4436
|
+
labelNames: ["template", "result"]
|
|
4437
|
+
});
|
|
4438
|
+
const stepCount = createCounterMetric({
|
|
4439
|
+
name: "scaffolder_step_count",
|
|
4440
|
+
help: "Count of step runs",
|
|
4441
|
+
labelNames: ["template", "step", "result"]
|
|
4442
|
+
});
|
|
4443
|
+
const stepDuration = createHistogramMetric({
|
|
4444
|
+
name: "scaffolder_step_duration",
|
|
4445
|
+
help: "Duration of a step runs",
|
|
4446
|
+
labelNames: ["template", "step", "result"]
|
|
4447
|
+
});
|
|
4448
|
+
async function taskStart(task) {
|
|
4449
|
+
var _a, _b;
|
|
4450
|
+
await task.emitLog(`Starting up task with ${task.spec.steps.length} steps`);
|
|
4451
|
+
const template = ((_a = task.spec.templateInfo) == null ? void 0 : _a.entityRef) || "";
|
|
4452
|
+
const user = ((_b = task.spec.user) == null ? void 0 : _b.ref) || "";
|
|
4453
|
+
const taskTimer = taskDuration.startTimer({
|
|
4454
|
+
template
|
|
4455
|
+
});
|
|
4456
|
+
async function skipDryRun(step, action) {
|
|
4457
|
+
task.emitLog(`Skipping because ${action.id} does not support dry-run`, {
|
|
4458
|
+
stepId: step.id,
|
|
4459
|
+
status: "skipped"
|
|
4460
|
+
});
|
|
4461
|
+
}
|
|
4462
|
+
async function markSuccessful() {
|
|
4463
|
+
taskCount.inc({
|
|
4464
|
+
template,
|
|
4465
|
+
user,
|
|
4466
|
+
result: "ok"
|
|
4467
|
+
});
|
|
4468
|
+
taskTimer({ result: "ok" });
|
|
4469
|
+
}
|
|
4470
|
+
async function markFailed(step, err) {
|
|
4471
|
+
await task.emitLog(String(err.stack), {
|
|
4472
|
+
stepId: step.id,
|
|
4473
|
+
status: "failed"
|
|
4474
|
+
});
|
|
4475
|
+
taskCount.inc({
|
|
4476
|
+
template,
|
|
4477
|
+
user,
|
|
4478
|
+
result: "failed"
|
|
4479
|
+
});
|
|
4480
|
+
taskTimer({ result: "failed" });
|
|
4481
|
+
}
|
|
4482
|
+
return {
|
|
4483
|
+
skipDryRun,
|
|
4484
|
+
markSuccessful,
|
|
4485
|
+
markFailed
|
|
4486
|
+
};
|
|
4487
|
+
}
|
|
4488
|
+
async function stepStart(task, step) {
|
|
4489
|
+
var _a;
|
|
4490
|
+
await task.emitLog(`Beginning step ${step.name}`, {
|
|
4491
|
+
stepId: step.id,
|
|
4492
|
+
status: "processing"
|
|
4493
|
+
});
|
|
4494
|
+
const template = ((_a = task.spec.templateInfo) == null ? void 0 : _a.entityRef) || "";
|
|
4495
|
+
const stepTimer = stepDuration.startTimer({
|
|
4496
|
+
template,
|
|
4497
|
+
step: step.name
|
|
4498
|
+
});
|
|
4499
|
+
async function markSuccessful() {
|
|
4500
|
+
await task.emitLog(`Finished step ${step.name}`, {
|
|
4501
|
+
stepId: step.id,
|
|
4502
|
+
status: "completed"
|
|
4503
|
+
});
|
|
4504
|
+
stepCount.inc({
|
|
4505
|
+
template,
|
|
4506
|
+
step: step.name,
|
|
4507
|
+
result: "ok"
|
|
4508
|
+
});
|
|
4509
|
+
stepTimer({ result: "ok" });
|
|
4510
|
+
}
|
|
4511
|
+
async function markFailed() {
|
|
4512
|
+
stepCount.inc({
|
|
4513
|
+
template,
|
|
4514
|
+
step: step.name,
|
|
4515
|
+
result: "failed"
|
|
4516
|
+
});
|
|
4517
|
+
stepTimer({ result: "failed" });
|
|
4518
|
+
}
|
|
4519
|
+
async function skipFalsy() {
|
|
4520
|
+
await task.emitLog(
|
|
4521
|
+
`Skipping step ${step.id} because its if condition was false`,
|
|
4522
|
+
{ stepId: step.id, status: "skipped" }
|
|
4523
|
+
);
|
|
4524
|
+
stepTimer({ result: "skipped" });
|
|
4525
|
+
}
|
|
4526
|
+
return {
|
|
4527
|
+
markSuccessful,
|
|
4528
|
+
markFailed,
|
|
4529
|
+
skipFalsy
|
|
4530
|
+
};
|
|
4531
|
+
}
|
|
4532
|
+
return {
|
|
4533
|
+
taskStart,
|
|
4534
|
+
stepStart
|
|
4535
|
+
};
|
|
4536
|
+
}
|
|
4426
4537
|
|
|
4427
4538
|
class TaskWorker {
|
|
4428
4539
|
constructor(options) {
|