@flakiness/sdk 0.151.0 → 0.152.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/lib/browser.js +52 -5
- package/lib/index.js +285 -162
- package/package.json +3 -5
- package/types/src/_telemetry.d.ts +7 -0
- package/types/src/_telemetry.d.ts.map +1 -0
- package/types/src/collectSources.d.ts +14 -0
- package/types/src/collectSources.d.ts.map +1 -0
- package/types/src/cpuUtilization.d.ts +30 -0
- package/types/src/cpuUtilization.d.ts.map +1 -0
- package/types/src/createEnvironment.d.ts +4 -8
- package/types/src/createEnvironment.d.ts.map +1 -1
- package/types/src/index.d.ts +2 -1
- package/types/src/index.d.ts.map +1 -1
- package/types/src/normalizeReport.d.ts +1 -0
- package/types/src/normalizeReport.d.ts.map +1 -1
- package/types/src/ramUtilization.d.ts +28 -0
- package/types/src/ramUtilization.d.ts.map +1 -0
- package/types/src/reportUtils.d.ts +1 -1
- package/types/src/reportUtils.d.ts.map +1 -1
- package/types/src/createTestStepSnippets.d.ts +0 -30
- package/types/src/createTestStepSnippets.d.ts.map +0 -1
- package/types/src/systemUtilizationSampler.d.ts +0 -43
- package/types/src/systemUtilizationSampler.d.ts.map +0 -1
package/lib/browser.js
CHANGED
|
@@ -29,6 +29,47 @@ var Multimap = class {
|
|
|
29
29
|
}
|
|
30
30
|
};
|
|
31
31
|
function normalizeReport(report) {
|
|
32
|
+
report = deduplicateTestsSuitesEnvironments(report);
|
|
33
|
+
function cleanupTestStep(step) {
|
|
34
|
+
return {
|
|
35
|
+
...step,
|
|
36
|
+
duration: step.duration === 0 ? void 0 : step.duration,
|
|
37
|
+
steps: step.steps && step.steps.length ? step.steps.map(cleanupTestStep) : void 0
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function cleanupAttempt(attempt) {
|
|
41
|
+
return {
|
|
42
|
+
...attempt,
|
|
43
|
+
status: attempt.status === "passed" ? void 0 : attempt.status,
|
|
44
|
+
expectedStatus: attempt.expectedStatus === "passed" ? void 0 : attempt.expectedStatus,
|
|
45
|
+
environmentIdx: attempt.environmentIdx === 0 ? void 0 : attempt.environmentIdx,
|
|
46
|
+
duration: attempt.duration === 0 ? void 0 : attempt.duration,
|
|
47
|
+
stdout: attempt.stdout && attempt.stdout.length ? attempt.stdout : void 0,
|
|
48
|
+
stderr: attempt.stderr && attempt.stderr.length ? attempt.stderr : void 0,
|
|
49
|
+
attachments: attempt.attachments && attempt.attachments.length ? attempt.attachments : void 0,
|
|
50
|
+
steps: attempt.steps && attempt.steps.length ? attempt.steps.map(cleanupTestStep) : void 0
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function cleanupTest(test) {
|
|
54
|
+
return {
|
|
55
|
+
...test,
|
|
56
|
+
attempts: test.attempts.map(cleanupAttempt)
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function cleanupSuite(suite) {
|
|
60
|
+
return {
|
|
61
|
+
...suite,
|
|
62
|
+
tests: suite.tests && suite.tests.length ? suite.tests.map(cleanupTest) : void 0,
|
|
63
|
+
suites: suite.suites && suite.suites.length ? suite.suites.map(cleanupSuite) : void 0
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
...report,
|
|
68
|
+
tests: report.tests && report.tests.length ? report.tests.map(cleanupTest) : void 0,
|
|
69
|
+
suites: report.suites && report.suites.length ? report.suites.map(cleanupSuite) : void 0
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function deduplicateTestsSuitesEnvironments(report) {
|
|
32
73
|
const gEnvs = /* @__PURE__ */ new Map();
|
|
33
74
|
const gSuites = /* @__PURE__ */ new Map();
|
|
34
75
|
const gTests = new Multimap();
|
|
@@ -50,9 +91,15 @@ function normalizeReport(report) {
|
|
|
50
91
|
gTestIds.set(test, testId);
|
|
51
92
|
gSuiteTests.set(suiteId, test);
|
|
52
93
|
for (const attempt of test.attempts) {
|
|
53
|
-
const env = report.environments[attempt.environmentIdx];
|
|
94
|
+
const env = report.environments[attempt.environmentIdx ?? 0];
|
|
54
95
|
const envId = gEnvIds.get(env);
|
|
55
96
|
usedEnvIds.add(envId);
|
|
97
|
+
if (attempt.annotations && !attempt.annotations.length)
|
|
98
|
+
delete attempt.annotations;
|
|
99
|
+
if (attempt.stdout && !attempt.stdout.length)
|
|
100
|
+
delete attempt.stdout;
|
|
101
|
+
if (attempt.stderr && !attempt.stderr.length)
|
|
102
|
+
delete attempt.stderr;
|
|
56
103
|
}
|
|
57
104
|
}
|
|
58
105
|
}
|
|
@@ -77,7 +124,7 @@ function normalizeReport(report) {
|
|
|
77
124
|
tags: tags.length ? tags : void 0,
|
|
78
125
|
attempts: tests2.map((t) => t.attempts).flat().map((attempt) => ({
|
|
79
126
|
...attempt,
|
|
80
|
-
environmentIdx: envIdToIndex.get(gEnvIds.get(report.environments[attempt.environmentIdx]))
|
|
127
|
+
environmentIdx: envIdToIndex.get(gEnvIds.get(report.environments[attempt.environmentIdx ?? 0]))
|
|
81
128
|
}))
|
|
82
129
|
};
|
|
83
130
|
});
|
|
@@ -96,14 +143,14 @@ function normalizeReport(report) {
|
|
|
96
143
|
});
|
|
97
144
|
}
|
|
98
145
|
visitTests2(report.tests ?? [], "suiteless");
|
|
99
|
-
for (const suite of report.suites)
|
|
146
|
+
for (const suite of report.suites ?? [])
|
|
100
147
|
visitSuite(suite);
|
|
101
148
|
const newEnvironments = [...usedEnvIds];
|
|
102
149
|
const envIdToIndex = new Map(newEnvironments.map((envId, index) => [envId, index]));
|
|
103
150
|
return {
|
|
104
151
|
...report,
|
|
105
152
|
environments: newEnvironments.map((envId) => gEnvs.get(envId)),
|
|
106
|
-
suites: transformSuites(report.suites),
|
|
153
|
+
suites: transformSuites(report.suites ?? []),
|
|
107
154
|
tests: transformTests(report.tests ?? [])
|
|
108
155
|
};
|
|
109
156
|
}
|
|
@@ -144,7 +191,7 @@ function visitTests(report, testVisitor) {
|
|
|
144
191
|
}
|
|
145
192
|
for (const test of report.tests ?? [])
|
|
146
193
|
testVisitor(test, []);
|
|
147
|
-
for (const suite of report.suites)
|
|
194
|
+
for (const suite of report.suites ?? [])
|
|
148
195
|
visitSuite(suite, []);
|
|
149
196
|
}
|
|
150
197
|
export {
|
package/lib/index.js
CHANGED
|
@@ -46,6 +46,86 @@ function azure() {
|
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
// src/cpuUtilization.ts
|
|
50
|
+
import os from "os";
|
|
51
|
+
|
|
52
|
+
// src/_telemetry.ts
|
|
53
|
+
function addTelemetryPoint(collection, newPoint, precision) {
|
|
54
|
+
const lastPoint = collection.at(-1);
|
|
55
|
+
const preLastPoint = collection.at(-2);
|
|
56
|
+
if (lastPoint && preLastPoint && Math.abs(lastPoint.value - preLastPoint.value) < precision && Math.abs(lastPoint.value - newPoint.value) < precision) {
|
|
57
|
+
lastPoint.timestamp = newPoint.timestamp;
|
|
58
|
+
} else {
|
|
59
|
+
collection.push(newPoint);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function toProtocolTelemetry(collection) {
|
|
63
|
+
if (!collection.length)
|
|
64
|
+
return [];
|
|
65
|
+
let lastTimestamp = collection[0].timestamp;
|
|
66
|
+
return collection.map((x, idx) => {
|
|
67
|
+
const dts = idx === 0 ? x.timestamp : x.timestamp - lastTimestamp;
|
|
68
|
+
lastTimestamp = x.timestamp;
|
|
69
|
+
return [dts, Math.round(x.value * 100) / 100];
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// src/cpuUtilization.ts
|
|
74
|
+
function sampleCpus() {
|
|
75
|
+
return os.cpus().map((cpu) => {
|
|
76
|
+
const totalTicks = cpu.times.user + cpu.times.nice + cpu.times.sys + cpu.times.irq + cpu.times.idle;
|
|
77
|
+
const idleTicks = cpu.times.idle;
|
|
78
|
+
const busyTicks = totalTicks - idleTicks;
|
|
79
|
+
return { totalTicks, busyTicks };
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
var CPUUtilization = class {
|
|
83
|
+
_lastSample = sampleCpus();
|
|
84
|
+
_precision;
|
|
85
|
+
_cpuAvg = [];
|
|
86
|
+
_cpuMax = [];
|
|
87
|
+
/**
|
|
88
|
+
* @param options.precision - Minimum change in percentage points to record a new data point. Defaults to 7.
|
|
89
|
+
*/
|
|
90
|
+
constructor(options) {
|
|
91
|
+
this._precision = options?.precision ?? 7;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Records the current CPU utilization since the last sample.
|
|
95
|
+
* The first call primes the baseline; subsequent calls record deltas.
|
|
96
|
+
*/
|
|
97
|
+
sample() {
|
|
98
|
+
const newSample = sampleCpus();
|
|
99
|
+
if (newSample.length === this._lastSample.length) {
|
|
100
|
+
const utilization = newSample.map(
|
|
101
|
+
(cpu, idx) => (
|
|
102
|
+
// If the CPU did no work since the last sample, then it's
|
|
103
|
+
// utilization is effectively 0.
|
|
104
|
+
cpu.totalTicks === this._lastSample[idx].totalTicks ? 0 : (cpu.busyTicks - this._lastSample[idx].busyTicks) / (cpu.totalTicks - this._lastSample[idx].totalTicks) * 100
|
|
105
|
+
)
|
|
106
|
+
);
|
|
107
|
+
const timestamp = Date.now();
|
|
108
|
+
addTelemetryPoint(this._cpuAvg, {
|
|
109
|
+
timestamp,
|
|
110
|
+
value: utilization.reduce((acc, x) => acc + x) / utilization.length
|
|
111
|
+
}, this._precision);
|
|
112
|
+
addTelemetryPoint(this._cpuMax, {
|
|
113
|
+
timestamp,
|
|
114
|
+
value: Math.max(...utilization)
|
|
115
|
+
}, this._precision);
|
|
116
|
+
}
|
|
117
|
+
this._lastSample = newSample;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Adds collected CPU telemetry to the report.
|
|
121
|
+
*/
|
|
122
|
+
enrich(report) {
|
|
123
|
+
report.cpuCount = os.cpus().length;
|
|
124
|
+
report.cpuMax = toProtocolTelemetry(this._cpuMax);
|
|
125
|
+
report.cpuAvg = toProtocolTelemetry(this._cpuAvg);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
|
|
49
129
|
// src/gitWorktree.ts
|
|
50
130
|
import assert from "assert";
|
|
51
131
|
import { exec } from "child_process";
|
|
@@ -335,23 +415,154 @@ async function listCommits(gitRoot, head, count) {
|
|
|
335
415
|
}
|
|
336
416
|
}
|
|
337
417
|
|
|
418
|
+
// src/ramUtilization.ts
|
|
419
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
420
|
+
import os2 from "os";
|
|
421
|
+
function getAvailableMemMacOS() {
|
|
422
|
+
const lines = spawnSync2("vm_stat", { encoding: "utf8" }).stdout.trim().split("\n");
|
|
423
|
+
const pageSize = parseInt(lines[0].match(/page size of (\d+) bytes/)[1], 10);
|
|
424
|
+
if (isNaN(pageSize)) {
|
|
425
|
+
console.warn("[flakiness.io] Error detecting macos page size");
|
|
426
|
+
return 0;
|
|
427
|
+
}
|
|
428
|
+
let totalFree = 0;
|
|
429
|
+
for (const line of lines) {
|
|
430
|
+
if (/Pages (free|inactive|speculative):/.test(line)) {
|
|
431
|
+
const match = line.match(/\d+/);
|
|
432
|
+
if (match)
|
|
433
|
+
totalFree += parseInt(match[0], 10);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
return totalFree * pageSize;
|
|
437
|
+
}
|
|
438
|
+
var RAMUtilization = class {
|
|
439
|
+
_precision;
|
|
440
|
+
_totalBytes = os2.totalmem();
|
|
441
|
+
_ram = [];
|
|
442
|
+
/**
|
|
443
|
+
* @param options.precision - Minimum change in percentage points to record a new data point. Defaults to 1.
|
|
444
|
+
*/
|
|
445
|
+
constructor(options) {
|
|
446
|
+
this._precision = options?.precision ?? 1;
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Records the current RAM utilization.
|
|
450
|
+
*/
|
|
451
|
+
sample() {
|
|
452
|
+
const freeBytes = os2.platform() === "darwin" ? getAvailableMemMacOS() : os2.freemem();
|
|
453
|
+
addTelemetryPoint(this._ram, {
|
|
454
|
+
timestamp: Date.now(),
|
|
455
|
+
value: (this._totalBytes - freeBytes) / this._totalBytes * 100
|
|
456
|
+
}, this._precision);
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Adds collected RAM telemetry to the report.
|
|
460
|
+
*/
|
|
461
|
+
enrich(report) {
|
|
462
|
+
report.ramBytes = this._totalBytes;
|
|
463
|
+
report.ram = toProtocolTelemetry(this._ram);
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
|
|
338
467
|
// src/reportUtils.ts
|
|
339
468
|
var reportUtils_exports = {};
|
|
340
469
|
__export(reportUtils_exports, {
|
|
470
|
+
collectSources: () => collectSources,
|
|
341
471
|
createDataAttachment: () => createDataAttachment,
|
|
342
472
|
createEnvironment: () => createEnvironment,
|
|
343
473
|
createFileAttachment: () => createFileAttachment,
|
|
344
|
-
createTestStepSnippetsInplace: () => createTestStepSnippetsInplace,
|
|
345
474
|
normalizeReport: () => normalizeReport,
|
|
346
475
|
stripAnsi: () => stripAnsi,
|
|
347
476
|
visitTests: () => visitTests
|
|
348
477
|
});
|
|
349
478
|
|
|
350
|
-
// src/
|
|
479
|
+
// src/collectSources.ts
|
|
351
480
|
import fs2 from "fs";
|
|
352
|
-
|
|
481
|
+
function collectLocationsFromTestStep(testStep, onLocation) {
|
|
482
|
+
onLocation(testStep.location);
|
|
483
|
+
for (const step of testStep.steps ?? [])
|
|
484
|
+
collectLocationsFromTestStep(step, onLocation);
|
|
485
|
+
}
|
|
486
|
+
function collectLocationsFromTest(test, onLocation) {
|
|
487
|
+
onLocation(test.location);
|
|
488
|
+
for (const attempt of test.attempts) {
|
|
489
|
+
for (const annotation of attempt.annotations ?? [])
|
|
490
|
+
onLocation(annotation.location);
|
|
491
|
+
for (const err of attempt.errors ?? [])
|
|
492
|
+
onLocation(err.location);
|
|
493
|
+
for (const step of attempt.steps ?? [])
|
|
494
|
+
collectLocationsFromTestStep(step, onLocation);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
function collectLocationsFromSuite(suite, onLocation) {
|
|
498
|
+
onLocation(suite.location);
|
|
499
|
+
for (const child of suite.suites ?? [])
|
|
500
|
+
collectLocationsFromSuite(child, onLocation);
|
|
501
|
+
for (const test of suite.tests ?? [])
|
|
502
|
+
collectLocationsFromTest(test, onLocation);
|
|
503
|
+
}
|
|
504
|
+
function collectLocationsFromReport(report, onLocation) {
|
|
505
|
+
for (const e of report.unattributedErrors ?? [])
|
|
506
|
+
onLocation(e.location);
|
|
507
|
+
for (const test of report.tests ?? [])
|
|
508
|
+
collectLocationsFromTest(test, onLocation);
|
|
509
|
+
for (const suite of report.suites ?? [])
|
|
510
|
+
collectLocationsFromSuite(suite, onLocation);
|
|
511
|
+
}
|
|
512
|
+
function lineNumbersToChunks(lineNumbers, options) {
|
|
513
|
+
const context = options.context;
|
|
514
|
+
const result = [];
|
|
515
|
+
let current;
|
|
516
|
+
for (const ln of Array.from(lineNumbers).sort((a, b) => a - b)) {
|
|
517
|
+
const span = [ln - context, ln + context];
|
|
518
|
+
if (!current || current[1] + 1 < span[0]) {
|
|
519
|
+
result.push(span);
|
|
520
|
+
current = span;
|
|
521
|
+
} else {
|
|
522
|
+
current[1] = span[1];
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
return result;
|
|
526
|
+
}
|
|
527
|
+
function collectSources(worktree, report) {
|
|
528
|
+
const filesToLines = /* @__PURE__ */ new Map();
|
|
529
|
+
collectLocationsFromReport(report, (location) => {
|
|
530
|
+
if (!location)
|
|
531
|
+
return;
|
|
532
|
+
let lineNumbers = filesToLines.get(location.file);
|
|
533
|
+
if (!lineNumbers) {
|
|
534
|
+
lineNumbers = /* @__PURE__ */ new Set();
|
|
535
|
+
filesToLines.set(location.file, lineNumbers);
|
|
536
|
+
}
|
|
537
|
+
lineNumbers.add(location.line);
|
|
538
|
+
});
|
|
539
|
+
const sources = [];
|
|
540
|
+
for (const [gitFilePath, lineNumbers] of filesToLines) {
|
|
541
|
+
let source;
|
|
542
|
+
try {
|
|
543
|
+
source = fs2.readFileSync(worktree.absolutePath(gitFilePath), "utf-8");
|
|
544
|
+
} catch (e) {
|
|
545
|
+
continue;
|
|
546
|
+
}
|
|
547
|
+
const sourceLines = source.split("\n");
|
|
548
|
+
for (const chunk of lineNumbersToChunks(lineNumbers, { context: 5 })) {
|
|
549
|
+
const from = Math.max(chunk[0] - 1, 0);
|
|
550
|
+
const to = Math.min(chunk[1], sourceLines.length);
|
|
551
|
+
sources.push({
|
|
552
|
+
filePath: gitFilePath,
|
|
553
|
+
lineOffset: from !== 0 ? from + 1 : void 0,
|
|
554
|
+
text: sourceLines.slice(from, to).join("\n")
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
report.sources = sources;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
// src/createEnvironment.ts
|
|
562
|
+
import fs3 from "fs";
|
|
563
|
+
import os3 from "os";
|
|
353
564
|
function readLinuxOSRelease() {
|
|
354
|
-
const osReleaseText =
|
|
565
|
+
const osReleaseText = fs3.readFileSync("/etc/os-release", "utf-8");
|
|
355
566
|
return new Map(osReleaseText.toLowerCase().split("\n").filter((line) => line.includes("=")).map((line) => {
|
|
356
567
|
line = line.trim();
|
|
357
568
|
let [key, value] = line.split("=");
|
|
@@ -376,7 +587,7 @@ function osDarwinInfo() {
|
|
|
376
587
|
function osWinInfo() {
|
|
377
588
|
const name = "win";
|
|
378
589
|
const arch = process.arch;
|
|
379
|
-
const version =
|
|
590
|
+
const version = os3.release();
|
|
380
591
|
return { name, arch, version };
|
|
381
592
|
}
|
|
382
593
|
function getOSInfo() {
|
|
@@ -401,74 +612,11 @@ function createEnvironment(options) {
|
|
|
401
612
|
osName: osInfo.name,
|
|
402
613
|
osVersion: osInfo.version
|
|
403
614
|
},
|
|
404
|
-
|
|
615
|
+
metadata: {
|
|
405
616
|
...extractEnvConfiguration(),
|
|
406
|
-
...options.
|
|
407
|
-
},
|
|
408
|
-
opaqueData: options.opaqueData
|
|
409
|
-
};
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
// src/createTestStepSnippets.ts
|
|
413
|
-
import { codeFrameColumns } from "@babel/code-frame";
|
|
414
|
-
import fs3 from "fs";
|
|
415
|
-
|
|
416
|
-
// src/visitTests.ts
|
|
417
|
-
function visitTests(report, testVisitor) {
|
|
418
|
-
function visitSuite(suite, parents) {
|
|
419
|
-
parents.push(suite);
|
|
420
|
-
for (const test of suite.tests ?? [])
|
|
421
|
-
testVisitor(test, parents);
|
|
422
|
-
for (const childSuite of suite.suites ?? [])
|
|
423
|
-
visitSuite(childSuite, parents);
|
|
424
|
-
parents.pop();
|
|
425
|
-
}
|
|
426
|
-
for (const test of report.tests ?? [])
|
|
427
|
-
testVisitor(test, []);
|
|
428
|
-
for (const suite of report.suites)
|
|
429
|
-
visitSuite(suite, []);
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
// src/createTestStepSnippets.ts
|
|
433
|
-
function createTestStepSnippetsInplace(worktree, report) {
|
|
434
|
-
const allSteps = /* @__PURE__ */ new Map();
|
|
435
|
-
visitTests(report, (test) => {
|
|
436
|
-
for (const attempt of test.attempts) {
|
|
437
|
-
for (const step of attempt.steps ?? []) {
|
|
438
|
-
if (!step.location)
|
|
439
|
-
continue;
|
|
440
|
-
let fileSteps = allSteps.get(step.location.file);
|
|
441
|
-
if (!fileSteps) {
|
|
442
|
-
fileSteps = /* @__PURE__ */ new Set();
|
|
443
|
-
allSteps.set(step.location.file, fileSteps);
|
|
444
|
-
}
|
|
445
|
-
fileSteps.add(step);
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
});
|
|
449
|
-
for (const [gitFilePath, steps] of allSteps) {
|
|
450
|
-
let source;
|
|
451
|
-
try {
|
|
452
|
-
source = fs3.readFileSync(worktree.absolutePath(gitFilePath), "utf-8");
|
|
453
|
-
} catch (e) {
|
|
454
|
-
continue;
|
|
455
|
-
}
|
|
456
|
-
const lines = source.split("\n").length;
|
|
457
|
-
const highlighted = codeFrameColumns(source, { start: { line: lines, column: 1 } }, { highlightCode: true, linesAbove: lines, linesBelow: 0 });
|
|
458
|
-
const highlightedLines = highlighted.split("\n");
|
|
459
|
-
const lineWithArrow = highlightedLines[highlightedLines.length - 1];
|
|
460
|
-
for (const step of steps) {
|
|
461
|
-
if (!step.location)
|
|
462
|
-
continue;
|
|
463
|
-
if (step.location.line < 2 || step.location.line >= lines)
|
|
464
|
-
continue;
|
|
465
|
-
const snippetLines = highlightedLines.slice(step.location.line - 2, step.location.line + 1);
|
|
466
|
-
const index = lineWithArrow.indexOf("^");
|
|
467
|
-
const shiftedArrow = lineWithArrow.slice(0, index) + " ".repeat(step.location.column - 1) + lineWithArrow.slice(index);
|
|
468
|
-
snippetLines.splice(2, 0, shiftedArrow);
|
|
469
|
-
step.snippet = snippetLines.join("\n");
|
|
617
|
+
...options.metadata ?? {}
|
|
470
618
|
}
|
|
471
|
-
}
|
|
619
|
+
};
|
|
472
620
|
}
|
|
473
621
|
|
|
474
622
|
// src/normalizeReport.ts
|
|
@@ -485,6 +633,47 @@ var Multimap = class {
|
|
|
485
633
|
}
|
|
486
634
|
};
|
|
487
635
|
function normalizeReport(report) {
|
|
636
|
+
report = deduplicateTestsSuitesEnvironments(report);
|
|
637
|
+
function cleanupTestStep(step) {
|
|
638
|
+
return {
|
|
639
|
+
...step,
|
|
640
|
+
duration: step.duration === 0 ? void 0 : step.duration,
|
|
641
|
+
steps: step.steps && step.steps.length ? step.steps.map(cleanupTestStep) : void 0
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
function cleanupAttempt(attempt) {
|
|
645
|
+
return {
|
|
646
|
+
...attempt,
|
|
647
|
+
status: attempt.status === "passed" ? void 0 : attempt.status,
|
|
648
|
+
expectedStatus: attempt.expectedStatus === "passed" ? void 0 : attempt.expectedStatus,
|
|
649
|
+
environmentIdx: attempt.environmentIdx === 0 ? void 0 : attempt.environmentIdx,
|
|
650
|
+
duration: attempt.duration === 0 ? void 0 : attempt.duration,
|
|
651
|
+
stdout: attempt.stdout && attempt.stdout.length ? attempt.stdout : void 0,
|
|
652
|
+
stderr: attempt.stderr && attempt.stderr.length ? attempt.stderr : void 0,
|
|
653
|
+
attachments: attempt.attachments && attempt.attachments.length ? attempt.attachments : void 0,
|
|
654
|
+
steps: attempt.steps && attempt.steps.length ? attempt.steps.map(cleanupTestStep) : void 0
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
function cleanupTest(test) {
|
|
658
|
+
return {
|
|
659
|
+
...test,
|
|
660
|
+
attempts: test.attempts.map(cleanupAttempt)
|
|
661
|
+
};
|
|
662
|
+
}
|
|
663
|
+
function cleanupSuite(suite) {
|
|
664
|
+
return {
|
|
665
|
+
...suite,
|
|
666
|
+
tests: suite.tests && suite.tests.length ? suite.tests.map(cleanupTest) : void 0,
|
|
667
|
+
suites: suite.suites && suite.suites.length ? suite.suites.map(cleanupSuite) : void 0
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
return {
|
|
671
|
+
...report,
|
|
672
|
+
tests: report.tests && report.tests.length ? report.tests.map(cleanupTest) : void 0,
|
|
673
|
+
suites: report.suites && report.suites.length ? report.suites.map(cleanupSuite) : void 0
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
function deduplicateTestsSuitesEnvironments(report) {
|
|
488
677
|
const gEnvs = /* @__PURE__ */ new Map();
|
|
489
678
|
const gSuites = /* @__PURE__ */ new Map();
|
|
490
679
|
const gTests = new Multimap();
|
|
@@ -506,9 +695,15 @@ function normalizeReport(report) {
|
|
|
506
695
|
gTestIds.set(test, testId);
|
|
507
696
|
gSuiteTests.set(suiteId, test);
|
|
508
697
|
for (const attempt of test.attempts) {
|
|
509
|
-
const env = report.environments[attempt.environmentIdx];
|
|
698
|
+
const env = report.environments[attempt.environmentIdx ?? 0];
|
|
510
699
|
const envId = gEnvIds.get(env);
|
|
511
700
|
usedEnvIds.add(envId);
|
|
701
|
+
if (attempt.annotations && !attempt.annotations.length)
|
|
702
|
+
delete attempt.annotations;
|
|
703
|
+
if (attempt.stdout && !attempt.stdout.length)
|
|
704
|
+
delete attempt.stdout;
|
|
705
|
+
if (attempt.stderr && !attempt.stderr.length)
|
|
706
|
+
delete attempt.stderr;
|
|
512
707
|
}
|
|
513
708
|
}
|
|
514
709
|
}
|
|
@@ -533,7 +728,7 @@ function normalizeReport(report) {
|
|
|
533
728
|
tags: tags.length ? tags : void 0,
|
|
534
729
|
attempts: tests2.map((t) => t.attempts).flat().map((attempt) => ({
|
|
535
730
|
...attempt,
|
|
536
|
-
environmentIdx: envIdToIndex.get(gEnvIds.get(report.environments[attempt.environmentIdx]))
|
|
731
|
+
environmentIdx: envIdToIndex.get(gEnvIds.get(report.environments[attempt.environmentIdx ?? 0]))
|
|
537
732
|
}))
|
|
538
733
|
};
|
|
539
734
|
});
|
|
@@ -552,14 +747,14 @@ function normalizeReport(report) {
|
|
|
552
747
|
});
|
|
553
748
|
}
|
|
554
749
|
visitTests2(report.tests ?? [], "suiteless");
|
|
555
|
-
for (const suite of report.suites)
|
|
750
|
+
for (const suite of report.suites ?? [])
|
|
556
751
|
visitSuite(suite);
|
|
557
752
|
const newEnvironments = [...usedEnvIds];
|
|
558
753
|
const envIdToIndex = new Map(newEnvironments.map((envId, index) => [envId, index]));
|
|
559
754
|
return {
|
|
560
755
|
...report,
|
|
561
756
|
environments: newEnvironments.map((envId) => gEnvs.get(envId)),
|
|
562
|
-
suites: transformSuites(report.suites),
|
|
757
|
+
suites: transformSuites(report.suites ?? []),
|
|
563
758
|
tests: transformTests(report.tests ?? [])
|
|
564
759
|
};
|
|
565
760
|
}
|
|
@@ -758,94 +953,21 @@ var ReportUpload = class {
|
|
|
758
953
|
}
|
|
759
954
|
};
|
|
760
955
|
|
|
761
|
-
// src/
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
}
|
|
771
|
-
let totalFree = 0;
|
|
772
|
-
for (const line of lines) {
|
|
773
|
-
if (/Pages (free|inactive|speculative):/.test(line)) {
|
|
774
|
-
const match = line.match(/\d+/);
|
|
775
|
-
if (match)
|
|
776
|
-
totalFree += parseInt(match[0], 10);
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
return totalFree * pageSize;
|
|
780
|
-
}
|
|
781
|
-
function getSystemUtilization() {
|
|
782
|
-
let idleTicks = 0;
|
|
783
|
-
let totalTicks = 0;
|
|
784
|
-
for (const cpu of os2.cpus()) {
|
|
785
|
-
totalTicks += cpu.times.user + cpu.times.nice + cpu.times.sys + cpu.times.irq + cpu.times.idle;
|
|
786
|
-
idleTicks += cpu.times.idle;
|
|
956
|
+
// src/visitTests.ts
|
|
957
|
+
function visitTests(report, testVisitor) {
|
|
958
|
+
function visitSuite(suite, parents) {
|
|
959
|
+
parents.push(suite);
|
|
960
|
+
for (const test of suite.tests ?? [])
|
|
961
|
+
testVisitor(test, parents);
|
|
962
|
+
for (const childSuite of suite.suites ?? [])
|
|
963
|
+
visitSuite(childSuite, parents);
|
|
964
|
+
parents.pop();
|
|
787
965
|
}
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
freeBytes: os2.platform() === "darwin" ? getAvailableMemMacOS() : os2.freemem()
|
|
793
|
-
};
|
|
794
|
-
}
|
|
795
|
-
function toFKUtilization(sample, previous) {
|
|
796
|
-
const idleTicks = sample.idleTicks - previous.idleTicks;
|
|
797
|
-
const totalTicks = sample.totalTicks - previous.totalTicks;
|
|
798
|
-
const cpuUtilization = Math.floor((1 - idleTicks / totalTicks) * 1e4) / 100;
|
|
799
|
-
const memoryUtilization = Math.floor((1 - sample.freeBytes / os2.totalmem()) * 1e4) / 100;
|
|
800
|
-
return {
|
|
801
|
-
cpuUtilization,
|
|
802
|
-
memoryUtilization,
|
|
803
|
-
dts: sample.timestamp - previous.timestamp
|
|
804
|
-
};
|
|
966
|
+
for (const test of report.tests ?? [])
|
|
967
|
+
testVisitor(test, []);
|
|
968
|
+
for (const suite of report.suites ?? [])
|
|
969
|
+
visitSuite(suite, []);
|
|
805
970
|
}
|
|
806
|
-
var SystemUtilizationSampler = class {
|
|
807
|
-
/**
|
|
808
|
-
* The accumulated system utilization data.
|
|
809
|
-
*
|
|
810
|
-
* This object is populated as samples are collected and can be directly included in
|
|
811
|
-
* Flakiness reports. It contains:
|
|
812
|
-
* - `samples` - Array of utilization samples with CPU/memory percentages and durations
|
|
813
|
-
* - `startTimestamp` - Timestamp when sampling began
|
|
814
|
-
* - `totalMemoryBytes` - Total system memory in bytes
|
|
815
|
-
*/
|
|
816
|
-
result;
|
|
817
|
-
_lastSample = getSystemUtilization();
|
|
818
|
-
_timer;
|
|
819
|
-
/**
|
|
820
|
-
* Creates a new SystemUtilizationSampler and starts sampling immediately.
|
|
821
|
-
*
|
|
822
|
-
* The first sample is collected after 50ms, and subsequent samples are collected
|
|
823
|
-
* every 1000ms. Call `dispose()` to stop sampling and clean up resources.
|
|
824
|
-
*/
|
|
825
|
-
constructor() {
|
|
826
|
-
this.result = {
|
|
827
|
-
samples: [],
|
|
828
|
-
startTimestamp: this._lastSample.timestamp,
|
|
829
|
-
totalMemoryBytes: os2.totalmem()
|
|
830
|
-
};
|
|
831
|
-
this._timer = setTimeout(this._addSample.bind(this), 50);
|
|
832
|
-
}
|
|
833
|
-
_addSample() {
|
|
834
|
-
const sample = getSystemUtilization();
|
|
835
|
-
this.result.samples.push(toFKUtilization(sample, this._lastSample));
|
|
836
|
-
this._lastSample = sample;
|
|
837
|
-
this._timer = setTimeout(this._addSample.bind(this), 1e3);
|
|
838
|
-
}
|
|
839
|
-
/**
|
|
840
|
-
* Stops sampling and cleans up resources.
|
|
841
|
-
*
|
|
842
|
-
* Call this method when you're done collecting utilization data to stop the sampling
|
|
843
|
-
* timer and prevent memory leaks. The `result` object remains accessible after disposal.
|
|
844
|
-
*/
|
|
845
|
-
dispose() {
|
|
846
|
-
clearTimeout(this._timer);
|
|
847
|
-
}
|
|
848
|
-
};
|
|
849
971
|
|
|
850
972
|
// src/showReport.ts
|
|
851
973
|
import chalk from "chalk";
|
|
@@ -1187,11 +1309,12 @@ async function writeReport(report, attachments, outputFolder) {
|
|
|
1187
1309
|
}
|
|
1188
1310
|
export {
|
|
1189
1311
|
CIUtils,
|
|
1312
|
+
CPUUtilization,
|
|
1190
1313
|
FlakinessProjectConfig,
|
|
1191
1314
|
FlakinessReport,
|
|
1192
1315
|
GitWorktree,
|
|
1316
|
+
RAMUtilization,
|
|
1193
1317
|
reportUtils_exports as ReportUtils,
|
|
1194
|
-
SystemUtilizationSampler,
|
|
1195
1318
|
showReport,
|
|
1196
1319
|
uploadReport,
|
|
1197
1320
|
writeReport
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flakiness/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.152.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
}
|
|
20
20
|
},
|
|
21
21
|
"type": "module",
|
|
22
|
-
"description": "",
|
|
22
|
+
"description": "Comprehensive SDK for creating and managing Flakiness JSON Reports in Node.js",
|
|
23
23
|
"types": "./types/index.d.ts",
|
|
24
24
|
"scripts": {
|
|
25
25
|
"minor": "./version.mjs minor",
|
|
@@ -29,7 +29,6 @@
|
|
|
29
29
|
"author": "Degu Labs, Inc",
|
|
30
30
|
"license": "MIT",
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@types/babel__code-frame": "^7.0.6",
|
|
33
32
|
"@types/debug": "^4.1.12",
|
|
34
33
|
"@types/node": "^25.0.3",
|
|
35
34
|
"esbuild": "^0.27.0",
|
|
@@ -38,8 +37,7 @@
|
|
|
38
37
|
"typescript": "^5.6.2"
|
|
39
38
|
},
|
|
40
39
|
"dependencies": {
|
|
41
|
-
"@
|
|
42
|
-
"@flakiness/flakiness-report": "^0.16.0",
|
|
40
|
+
"@flakiness/flakiness-report": "^0.18.0",
|
|
43
41
|
"chalk": "^5.6.2",
|
|
44
42
|
"debug": "^4.4.3",
|
|
45
43
|
"open": "^10.2.0",
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type TelemetryPoint = {
|
|
2
|
+
timestamp: number;
|
|
3
|
+
value: number;
|
|
4
|
+
};
|
|
5
|
+
export declare function addTelemetryPoint(collection: TelemetryPoint[], newPoint: TelemetryPoint, precision: number): void;
|
|
6
|
+
export declare function toProtocolTelemetry(collection: TelemetryPoint[]): [number, number][];
|
|
7
|
+
//# sourceMappingURL=_telemetry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_telemetry.d.ts","sourceRoot":"","sources":["../../src/_telemetry.ts"],"names":[],"mappings":"AACA,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,cAAc,EAAE,EAAE,QAAQ,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,QAY1G;AAED,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CASpF"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { FlakinessReport as FK } from '@flakiness/flakiness-report';
|
|
2
|
+
import { GitWorktree } from './gitWorktree.js';
|
|
3
|
+
/**
|
|
4
|
+
* Extracts source code snippets referenced by locations in the report.
|
|
5
|
+
*
|
|
6
|
+
* Scans all locations in the report (tests, steps, errors, annotations) and collects
|
|
7
|
+
* the relevant source code chunks with surrounding context (±5 lines). The collected
|
|
8
|
+
* sources are stored directly in `report.sources`.
|
|
9
|
+
*
|
|
10
|
+
* @param worktree - Git worktree for resolving file paths.
|
|
11
|
+
* @param report - Report to scan and enrich with source snippets.
|
|
12
|
+
*/
|
|
13
|
+
export declare function collectSources(worktree: GitWorktree, report: FK.Report): void;
|
|
14
|
+
//# sourceMappingURL=collectSources.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collectSources.d.ts","sourceRoot":"","sources":["../../src/collectSources.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,IAAI,EAAE,EAAE,MAAM,6BAA6B,CAAC;AAEpE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAqD/C;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,QAiCtE"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { FlakinessReport as FK } from "@flakiness/flakiness-report";
|
|
2
|
+
/**
|
|
3
|
+
* Tracks CPU utilization over time by recording periodic samples.
|
|
4
|
+
*
|
|
5
|
+
* Call `sample()` at desired intervals (e.g., test start/end, every second) to record
|
|
6
|
+
* CPU usage. The class tracks both average and max utilization across all CPU cores.
|
|
7
|
+
* Use `enrich()` to add the collected telemetry to a report.
|
|
8
|
+
*/
|
|
9
|
+
export declare class CPUUtilization {
|
|
10
|
+
private _lastSample;
|
|
11
|
+
private _precision;
|
|
12
|
+
private _cpuAvg;
|
|
13
|
+
private _cpuMax;
|
|
14
|
+
/**
|
|
15
|
+
* @param options.precision - Minimum change in percentage points to record a new data point. Defaults to 7.
|
|
16
|
+
*/
|
|
17
|
+
constructor(options?: {
|
|
18
|
+
precision?: number;
|
|
19
|
+
});
|
|
20
|
+
/**
|
|
21
|
+
* Records the current CPU utilization since the last sample.
|
|
22
|
+
* The first call primes the baseline; subsequent calls record deltas.
|
|
23
|
+
*/
|
|
24
|
+
sample(): void;
|
|
25
|
+
/**
|
|
26
|
+
* Adds collected CPU telemetry to the report.
|
|
27
|
+
*/
|
|
28
|
+
enrich(report: FK.Report): void;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=cpuUtilization.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cpuUtilization.d.ts","sourceRoot":"","sources":["../../src/cpuUtilization.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,IAAI,EAAE,EAAE,MAAM,6BAA6B,CAAC;AAkBpE;;;;;;GAMG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,WAAW,CAAgB;IAEnC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,OAAO,CAAwB;IAEvC;;OAEG;gBACS,OAAO,CAAC,EAAE;QACpB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB;IAID;;;OAGG;IACH,MAAM;IAwBN;;OAEG;IACH,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM;CAKzB"}
|
|
@@ -9,16 +9,13 @@ import { FlakinessReport } from '@flakiness/flakiness-report';
|
|
|
9
9
|
*
|
|
10
10
|
* @param {Object} options - Configuration object for the environment.
|
|
11
11
|
* @param {string} options.name - Human-readable name for the environment (e.g., 'CI', 'Local Dev', 'Staging').
|
|
12
|
-
* @param {Record<string, string>} [options.
|
|
12
|
+
* @param {Record<string, string>} [options.metadata] - Additional key-value pairs to include
|
|
13
13
|
* in the environment data. These are merged with `FK_ENV_*` environment variables.
|
|
14
|
-
* @param {any} [options.opaqueData] - Optional opaque data object that will be stored with the
|
|
15
|
-
* environment but not used for environment deduplication.
|
|
16
14
|
*
|
|
17
15
|
* @returns {FlakinessReport.Environment} Environment object containing:
|
|
18
16
|
* - `name` - The provided environment name
|
|
19
17
|
* - `systemData` - Automatically detected OS information (arch, name, version)
|
|
20
|
-
* - `
|
|
21
|
-
* - `opaqueData` - The provided opaque data, if any
|
|
18
|
+
* - `metadata` - Merged data from `FK_ENV_*` variables and `userSuppliedData` option
|
|
22
19
|
*
|
|
23
20
|
* @example
|
|
24
21
|
* ```typescript
|
|
@@ -28,13 +25,12 @@ import { FlakinessReport } from '@flakiness/flakiness-report';
|
|
|
28
25
|
* // With custom data
|
|
29
26
|
* const env = createEnvironment({
|
|
30
27
|
* name: 'Staging',
|
|
31
|
-
*
|
|
28
|
+
* metadata: { region: 'us-east-1', instance: 'large' }
|
|
32
29
|
* });
|
|
33
30
|
* ```
|
|
34
31
|
*/
|
|
35
32
|
export declare function createEnvironment(options: {
|
|
36
33
|
name: string;
|
|
37
|
-
|
|
38
|
-
opaqueData?: any;
|
|
34
|
+
metadata?: Record<string, string>;
|
|
39
35
|
}): FlakinessReport.Environment;
|
|
40
36
|
//# sourceMappingURL=createEnvironment.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createEnvironment.d.ts","sourceRoot":"","sources":["../../src/createEnvironment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAwD9D
|
|
1
|
+
{"version":3,"file":"createEnvironment.d.ts","sourceRoot":"","sources":["../../src/createEnvironment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAwD9D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC,GAAG,eAAe,CAAC,WAAW,CAc9B"}
|
package/types/src/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export { FlakinessReport } from '@flakiness/flakiness-report';
|
|
2
2
|
export { CIUtils } from './ciUtils.js';
|
|
3
|
+
export { CPUUtilization } from './cpuUtilization.js';
|
|
3
4
|
export { GitWorktree } from './gitWorktree.js';
|
|
5
|
+
export { RAMUtilization } from './ramUtilization.js';
|
|
4
6
|
export * as ReportUtils from './reportUtils.js';
|
|
5
|
-
export { SystemUtilizationSampler } from './systemUtilizationSampler.js';
|
|
6
7
|
export { showReport } from './showReport.js';
|
|
7
8
|
export { uploadReport } from './uploadReport.js';
|
|
8
9
|
export { writeReport } from './writeReport.js';
|
package/types/src/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAG9D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAG9D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAC;AAGhD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { FlakinessReport } from "@flakiness/flakiness-report";
|
|
2
2
|
/**
|
|
3
3
|
* Normalizes a Flakiness report by deduplicating environments, suites, and tests.
|
|
4
|
+
* It also drops the fields from JSON that are equal to their default values.
|
|
4
5
|
*
|
|
5
6
|
* This function processes a report to:
|
|
6
7
|
* - Deduplicate environments based on their content (using stable hashing)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"normalizeReport.d.ts","sourceRoot":"","sources":["../../src/normalizeReport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAyB9D
|
|
1
|
+
{"version":3,"file":"normalizeReport.d.ts","sourceRoot":"","sources":["../../src/normalizeReport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAyB9D;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,CAAC,MAAM,GAAG,eAAe,CAAC,MAAM,CA+CtF"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { FlakinessReport as FK } from '@flakiness/flakiness-report';
|
|
2
|
+
/**
|
|
3
|
+
* Tracks RAM utilization over time by recording periodic samples.
|
|
4
|
+
*
|
|
5
|
+
* Call `sample()` at desired intervals (e.g., test start/end, every second) to record
|
|
6
|
+
* memory usage as a percentage of total system RAM. Use `enrich()` to add the collected
|
|
7
|
+
* telemetry to a report.
|
|
8
|
+
*/
|
|
9
|
+
export declare class RAMUtilization {
|
|
10
|
+
private _precision;
|
|
11
|
+
private _totalBytes;
|
|
12
|
+
private _ram;
|
|
13
|
+
/**
|
|
14
|
+
* @param options.precision - Minimum change in percentage points to record a new data point. Defaults to 1.
|
|
15
|
+
*/
|
|
16
|
+
constructor(options?: {
|
|
17
|
+
precision?: number;
|
|
18
|
+
});
|
|
19
|
+
/**
|
|
20
|
+
* Records the current RAM utilization.
|
|
21
|
+
*/
|
|
22
|
+
sample(): void;
|
|
23
|
+
/**
|
|
24
|
+
* Adds collected RAM telemetry to the report.
|
|
25
|
+
*/
|
|
26
|
+
enrich(report: FK.Report): void;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=ramUtilization.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ramUtilization.d.ts","sourceRoot":"","sources":["../../src/ramUtilization.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,IAAI,EAAE,EAAE,MAAM,6BAA6B,CAAC;AA4BpE;;;;;;GAMG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAiB;IAEpC,OAAO,CAAC,IAAI,CAAwB;IAEpC;;OAEG;gBACS,OAAO,CAAC,EAAE;QACpB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB;IAID;;OAEG;IACH,MAAM;IAQN;;OAEG;IACH,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM;CAIzB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
export { collectSources } from './collectSources.js';
|
|
1
2
|
export { createEnvironment } from './createEnvironment.js';
|
|
2
|
-
export { createTestStepSnippetsInplace } from './createTestStepSnippets.js';
|
|
3
3
|
export { normalizeReport } from './normalizeReport.js';
|
|
4
4
|
export { stripAnsi } from './stripAnsi.js';
|
|
5
5
|
export { createDataAttachment, createFileAttachment } from './uploadReport.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reportUtils.d.ts","sourceRoot":"","sources":["../../src/reportUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"reportUtils.d.ts","sourceRoot":"","sources":["../../src/reportUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACrB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,UAAU,EAAE,cAAc,EAC1B,cAAc,EACf,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { FlakinessReport } from '@flakiness/flakiness-report';
|
|
2
|
-
import { GitWorktree } from './gitWorktree.js';
|
|
3
|
-
/**
|
|
4
|
-
* Generates code snippets for test steps and attaches them to the report in-place.
|
|
5
|
-
*
|
|
6
|
-
* This function reads source files from the git worktree and creates highlighted code snippets
|
|
7
|
-
* for each test step that has a location. The snippets include 3 lines of context (1 before,
|
|
8
|
-
* the line itself, 1 after) with syntax highlighting and a visual indicator pointing to the
|
|
9
|
-
* exact column position.
|
|
10
|
-
*
|
|
11
|
-
* The snippets are attached directly to the `step.snippet` property of each test step in the
|
|
12
|
-
* report object. Steps without locations or with invalid file paths are silently skipped.
|
|
13
|
-
*
|
|
14
|
-
* @param {GitWorktree} worktree - Git worktree instance used to resolve file paths from
|
|
15
|
-
* git-relative paths to absolute paths for reading source files.
|
|
16
|
-
*
|
|
17
|
-
* @param {FlakinessReport.Report} report - Flakiness report to process. The report is modified
|
|
18
|
-
* in-place by adding `snippet` properties to test steps.
|
|
19
|
-
*
|
|
20
|
-
* @returns {void} This function modifies the report in-place and does not return a value.
|
|
21
|
-
*
|
|
22
|
-
* @example
|
|
23
|
-
* ```typescript
|
|
24
|
-
* const worktree = GitWorktree.create(process.cwd());
|
|
25
|
-
* createTestStepSnippetsInplace(worktree, report);
|
|
26
|
-
* // Report steps now have .snippet properties with highlighted code
|
|
27
|
-
* ```
|
|
28
|
-
*/
|
|
29
|
-
export declare function createTestStepSnippetsInplace(worktree: GitWorktree, report: FlakinessReport.Report): void;
|
|
30
|
-
//# sourceMappingURL=createTestStepSnippets.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"createTestStepSnippets.d.ts","sourceRoot":"","sources":["../../src/createTestStepSnippets.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAE9D,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG/C;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,eAAe,CAAC,MAAM,QA4ClG"}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { FlakinessReport } from "@flakiness/flakiness-report";
|
|
2
|
-
/**
|
|
3
|
-
* Samples and records system CPU and memory utilization over time.
|
|
4
|
-
*
|
|
5
|
-
* This class continuously monitors system resource usage at regular intervals and stores
|
|
6
|
-
* the samples in a format suitable for inclusion in Flakiness reports. Sampling starts
|
|
7
|
-
* immediately upon construction and continues until `dispose()` is called.
|
|
8
|
-
*
|
|
9
|
-
* The first sample is collected after 50ms, and subsequent samples are collected every
|
|
10
|
-
* 1000ms (1 second). CPU utilization is calculated as a percentage based on CPU tick
|
|
11
|
-
* differences between samples. Memory utilization uses platform-specific methods for
|
|
12
|
-
* accurate measurement (especially on macOS).
|
|
13
|
-
*/
|
|
14
|
-
export declare class SystemUtilizationSampler {
|
|
15
|
-
/**
|
|
16
|
-
* The accumulated system utilization data.
|
|
17
|
-
*
|
|
18
|
-
* This object is populated as samples are collected and can be directly included in
|
|
19
|
-
* Flakiness reports. It contains:
|
|
20
|
-
* - `samples` - Array of utilization samples with CPU/memory percentages and durations
|
|
21
|
-
* - `startTimestamp` - Timestamp when sampling began
|
|
22
|
-
* - `totalMemoryBytes` - Total system memory in bytes
|
|
23
|
-
*/
|
|
24
|
-
readonly result: FlakinessReport.SystemUtilization;
|
|
25
|
-
private _lastSample;
|
|
26
|
-
private _timer;
|
|
27
|
-
/**
|
|
28
|
-
* Creates a new SystemUtilizationSampler and starts sampling immediately.
|
|
29
|
-
*
|
|
30
|
-
* The first sample is collected after 50ms, and subsequent samples are collected
|
|
31
|
-
* every 1000ms. Call `dispose()` to stop sampling and clean up resources.
|
|
32
|
-
*/
|
|
33
|
-
constructor();
|
|
34
|
-
private _addSample;
|
|
35
|
-
/**
|
|
36
|
-
* Stops sampling and cleans up resources.
|
|
37
|
-
*
|
|
38
|
-
* Call this method when you're done collecting utilization data to stop the sampling
|
|
39
|
-
* timer and prevent memory leaks. The `result` object remains accessible after disposal.
|
|
40
|
-
*/
|
|
41
|
-
dispose(): void;
|
|
42
|
-
}
|
|
43
|
-
//# sourceMappingURL=systemUtilizationSampler.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"systemUtilizationSampler.d.ts","sourceRoot":"","sources":["../../src/systemUtilizationSampler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AA6D9D;;;;;;;;;;;GAWG;AACH,qBAAa,wBAAwB;IACnC;;;;;;;;OAQG;IACH,SAAgB,MAAM,EAAE,eAAe,CAAC,iBAAiB,CAAC;IAE1D,OAAO,CAAC,WAAW,CAA0B;IAC7C,OAAO,CAAC,MAAM,CAAiB;IAE/B;;;;;OAKG;;IAWH,OAAO,CAAC,UAAU;IAOlB;;;;;OAKG;IACH,OAAO;CAGR"}
|