@flakiness/sdk 0.149.0 → 0.150.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.
Files changed (57) hide show
  1. package/README.md +9 -4
  2. package/lib/_internalUtils.js +2 -68
  3. package/lib/browser.js +2 -149
  4. package/lib/ciUtils.js +0 -1
  5. package/lib/createEnvironment.js +1 -105
  6. package/lib/createTestStepSnippets.js +1 -19
  7. package/lib/flakinessProjectConfig.js +6 -317
  8. package/lib/gitWorktree.js +8 -112
  9. package/lib/index.js +9 -1244
  10. package/lib/normalizeReport.js +2 -3
  11. package/lib/reportUtils.js +9 -384
  12. package/lib/reportUtilsBrowser.js +3 -132
  13. package/lib/showReport.js +3 -612
  14. package/lib/staticServer.js +7 -8
  15. package/lib/stripAnsi.js +1 -2
  16. package/lib/systemUtilizationSampler.js +2 -3
  17. package/lib/uploadReport.js +33 -148
  18. package/lib/visitTests.js +0 -1
  19. package/lib/writeReport.js +0 -1
  20. package/package.json +14 -5
  21. package/types/src/_internalUtils.d.ts +13 -0
  22. package/types/src/_internalUtils.d.ts.map +1 -0
  23. package/types/src/browser.d.ts +3 -0
  24. package/types/src/browser.d.ts.map +1 -0
  25. package/types/src/ciUtils.d.ts +33 -0
  26. package/types/src/ciUtils.d.ts.map +1 -0
  27. package/types/src/createEnvironment.d.ts +40 -0
  28. package/types/src/createEnvironment.d.ts.map +1 -0
  29. package/types/src/createTestStepSnippets.d.ts +30 -0
  30. package/types/src/createTestStepSnippets.d.ts.map +1 -0
  31. package/types/src/flakinessProjectConfig.d.ts +103 -0
  32. package/types/src/flakinessProjectConfig.d.ts.map +1 -0
  33. package/types/src/gitWorktree.d.ts +139 -0
  34. package/types/src/gitWorktree.d.ts.map +1 -0
  35. package/types/src/index.d.ts +10 -0
  36. package/types/src/index.d.ts.map +1 -0
  37. package/types/src/normalizeReport.d.ts +26 -0
  38. package/types/src/normalizeReport.d.ts.map +1 -0
  39. package/types/src/reportUtils.d.ts +7 -0
  40. package/types/src/reportUtils.d.ts.map +1 -0
  41. package/types/src/reportUtilsBrowser.d.ts +4 -0
  42. package/types/src/reportUtilsBrowser.d.ts.map +1 -0
  43. package/types/src/showReport.d.ts +18 -0
  44. package/types/src/showReport.d.ts.map +1 -0
  45. package/types/src/staticServer.d.ts +16 -0
  46. package/types/src/staticServer.d.ts.map +1 -0
  47. package/types/src/stripAnsi.d.ts +19 -0
  48. package/types/src/stripAnsi.d.ts.map +1 -0
  49. package/types/src/systemUtilizationSampler.d.ts +43 -0
  50. package/types/src/systemUtilizationSampler.d.ts.map +1 -0
  51. package/types/src/uploadReport.d.ts +196 -0
  52. package/types/src/uploadReport.d.ts.map +1 -0
  53. package/types/src/visitTests.d.ts +28 -0
  54. package/types/src/visitTests.d.ts.map +1 -0
  55. package/types/src/writeReport.d.ts +45 -0
  56. package/types/src/writeReport.d.ts.map +1 -0
  57. package/types/tsconfig.tsbuildinfo +0 -1
package/README.md CHANGED
@@ -1,11 +1,16 @@
1
- # Flakiness SDK
1
+ # Flakiness Node.js SDK
2
2
 
3
- The Flakiness SDK provides a comprehensive set of tools for creating and managing Flakiness Reports in Node.js.
3
+ The Flakiness SDK provides a comprehensive set of tools for creating and managing [Flakiness JSON Reports](https://github.com/flakiness/flakiness-report) in Node.js.
4
4
 
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm i @flakiness/sdk
9
+ ```
5
10
 
6
11
  ## Quick Start
7
12
 
8
- Here's a minimal example of creating a Flakiness report:
13
+ Here's a minimal example of creating a Flakiness JSON Report:
9
14
 
10
15
  ```typescript
11
16
  import {
@@ -74,7 +79,7 @@ Use this entry point when you need to process or manipulate reports in browser-b
74
79
  ## Top-Level Exports
75
80
 
76
81
  ### Report Type & Validation
77
- - **`FlakinessReport`** - Type definitions and validation for the Flakiness JSON Report format
82
+ - **`FlakinessReport`** - Type definitions and validation for the [Flakiness JSON Report](https://github.com/flakiness/flakiness-report) format
78
83
 
79
84
  ### Building Reports
80
85
  - **`CIUtils`** - Utilities to extract CI/CD information (run URLs, environment detection)
@@ -1,12 +1,9 @@
1
- // src/_internalUtils.ts
2
1
  import { spawnSync } from "child_process";
3
2
  import crypto from "crypto";
4
3
  import fs from "fs";
5
- import http from "http";
6
- import https from "https";
7
4
  import util from "util";
8
5
  import zlib from "zlib";
9
- var asyncBrotliCompress = util.promisify(zlib.brotliCompress);
6
+ const asyncBrotliCompress = util.promisify(zlib.brotliCompress);
10
7
  async function compressTextAsync(text) {
11
8
  return asyncBrotliCompress(text, {
12
9
  chunkSize: 32 * 1024,
@@ -16,7 +13,7 @@ async function compressTextAsync(text) {
16
13
  }
17
14
  });
18
15
  }
19
- var FLAKINESS_DBG = !!process.env.FLAKINESS_DBG;
16
+ const FLAKINESS_DBG = !!process.env.FLAKINESS_DBG;
20
17
  function errorText(error) {
21
18
  return FLAKINESS_DBG ? error.stack : error.message;
22
19
  }
@@ -36,68 +33,6 @@ async function retryWithBackoff(job, backoff = []) {
36
33
  }
37
34
  return await job();
38
35
  }
39
- var httpUtils;
40
- ((httpUtils2) => {
41
- function createRequest({ url, method = "get", headers = {} }) {
42
- let resolve;
43
- let reject;
44
- const responseDataPromise = new Promise((a, b) => {
45
- resolve = a;
46
- reject = b;
47
- });
48
- const protocol = url.startsWith("https") ? https : http;
49
- headers = Object.fromEntries(Object.entries(headers).filter(([key, value]) => value !== void 0));
50
- const request = protocol.request(url, { method, headers }, (res) => {
51
- const chunks = [];
52
- res.on("data", (chunk) => chunks.push(chunk));
53
- res.on("end", () => {
54
- if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300)
55
- resolve(Buffer.concat(chunks));
56
- else
57
- reject(new Error(`Request to ${url} failed with ${res.statusCode}`));
58
- });
59
- res.on("error", (error) => reject(error));
60
- });
61
- request.on("error", reject);
62
- return { request, responseDataPromise };
63
- }
64
- httpUtils2.createRequest = createRequest;
65
- async function getBuffer(url, backoff) {
66
- return await retryWithBackoff(async () => {
67
- const { request, responseDataPromise } = createRequest({ url });
68
- request.end();
69
- return await responseDataPromise;
70
- }, backoff);
71
- }
72
- httpUtils2.getBuffer = getBuffer;
73
- async function getText(url, backoff) {
74
- const buffer = await getBuffer(url, backoff);
75
- return buffer.toString("utf-8");
76
- }
77
- httpUtils2.getText = getText;
78
- async function getJSON(url) {
79
- return JSON.parse(await getText(url));
80
- }
81
- httpUtils2.getJSON = getJSON;
82
- async function postText(url, text, backoff) {
83
- const headers = {
84
- "Content-Type": "application/json",
85
- "Content-Length": Buffer.byteLength(text) + ""
86
- };
87
- return await retryWithBackoff(async () => {
88
- const { request, responseDataPromise } = createRequest({ url, headers, method: "post" });
89
- request.write(text);
90
- request.end();
91
- return await responseDataPromise;
92
- }, backoff);
93
- }
94
- httpUtils2.postText = postText;
95
- async function postJSON(url, json, backoff) {
96
- const buffer = await postText(url, JSON.stringify(json), backoff);
97
- return JSON.parse(buffer.toString("utf-8"));
98
- }
99
- httpUtils2.postJSON = postJSON;
100
- })(httpUtils || (httpUtils = {}));
101
36
  function shell(command, args, options) {
102
37
  try {
103
38
  const result = spawnSync(command, args, { encoding: "utf-8", ...options });
@@ -146,7 +81,6 @@ function randomUUIDBase62() {
146
81
  export {
147
82
  compressTextAsync,
148
83
  errorText,
149
- httpUtils,
150
84
  randomUUIDBase62,
151
85
  retryWithBackoff,
152
86
  sha1File,
package/lib/browser.js CHANGED
@@ -1,154 +1,7 @@
1
- var __defProp = Object.defineProperty;
2
- var __export = (target, all) => {
3
- for (var name in all)
4
- __defProp(target, name, { get: all[name], enumerable: true });
5
- };
6
-
7
- // src/browser.ts
8
1
  import { FlakinessReport } from "@flakiness/flakiness-report";
9
-
10
- // src/reportUtilsBrowser.ts
11
- var reportUtilsBrowser_exports = {};
12
- __export(reportUtilsBrowser_exports, {
13
- normalizeReport: () => normalizeReport,
14
- stripAnsi: () => stripAnsi,
15
- visitTests: () => visitTests
16
- });
17
-
18
- // src/normalizeReport.ts
19
- import stableObjectHash from "stable-hash";
20
- var Multimap = class {
21
- _map = /* @__PURE__ */ new Map();
22
- set(key, value) {
23
- const set = this._map.get(key) ?? /* @__PURE__ */ new Set();
24
- this._map.set(key, set);
25
- set.add(value);
26
- }
27
- getAll(key) {
28
- return Array.from(this._map.get(key) ?? []);
29
- }
30
- };
31
- function normalizeReport(report) {
32
- const gEnvs = /* @__PURE__ */ new Map();
33
- const gSuites = /* @__PURE__ */ new Map();
34
- const gTests = new Multimap();
35
- const gSuiteIds = /* @__PURE__ */ new Map();
36
- const gTestIds = /* @__PURE__ */ new Map();
37
- const gEnvIds = /* @__PURE__ */ new Map();
38
- const gSuiteChildren = new Multimap();
39
- const gSuiteTests = new Multimap();
40
- for (const env of report.environments) {
41
- const envId = computeEnvId(env);
42
- gEnvs.set(envId, env);
43
- gEnvIds.set(env, envId);
44
- }
45
- const usedEnvIds = /* @__PURE__ */ new Set();
46
- function visitTests2(tests, suiteId) {
47
- for (const test of tests ?? []) {
48
- const testId = computeTestId(test, suiteId);
49
- gTests.set(testId, test);
50
- gTestIds.set(test, testId);
51
- gSuiteTests.set(suiteId, test);
52
- for (const attempt of test.attempts) {
53
- const env = report.environments[attempt.environmentIdx];
54
- const envId = gEnvIds.get(env);
55
- usedEnvIds.add(envId);
56
- }
57
- }
58
- }
59
- function visitSuite(suite, parentSuiteId) {
60
- const suiteId = computeSuiteId(suite, parentSuiteId);
61
- gSuites.set(suiteId, suite);
62
- gSuiteIds.set(suite, suiteId);
63
- for (const childSuite of suite.suites ?? []) {
64
- visitSuite(childSuite, suiteId);
65
- gSuiteChildren.set(suiteId, childSuite);
66
- }
67
- visitTests2(suite.tests ?? [], suiteId);
68
- }
69
- function transformTests(tests) {
70
- const testIds = new Set(tests.map((test) => gTestIds.get(test)));
71
- return [...testIds].map((testId) => {
72
- const tests2 = gTests.getAll(testId);
73
- const tags = tests2.map((test) => test.tags ?? []).flat();
74
- return {
75
- location: tests2[0].location,
76
- title: tests2[0].title,
77
- tags: tags.length ? tags : void 0,
78
- attempts: tests2.map((t) => t.attempts).flat().map((attempt) => ({
79
- ...attempt,
80
- environmentIdx: envIdToIndex.get(gEnvIds.get(report.environments[attempt.environmentIdx]))
81
- }))
82
- };
83
- });
84
- }
85
- function transformSuites(suites) {
86
- const suiteIds = new Set(suites.map((suite) => gSuiteIds.get(suite)));
87
- return [...suiteIds].map((suiteId) => {
88
- const suite = gSuites.get(suiteId);
89
- return {
90
- location: suite.location,
91
- title: suite.title,
92
- type: suite.type,
93
- suites: transformSuites(gSuiteChildren.getAll(suiteId)),
94
- tests: transformTests(gSuiteTests.getAll(suiteId))
95
- };
96
- });
97
- }
98
- visitTests2(report.tests ?? [], "suiteless");
99
- for (const suite of report.suites)
100
- visitSuite(suite);
101
- const newEnvironments = [...usedEnvIds];
102
- const envIdToIndex = new Map(newEnvironments.map((envId, index) => [envId, index]));
103
- return {
104
- ...report,
105
- environments: newEnvironments.map((envId) => gEnvs.get(envId)),
106
- suites: transformSuites(report.suites),
107
- tests: transformTests(report.tests ?? [])
108
- };
109
- }
110
- function computeEnvId(env) {
111
- return stableObjectHash(env);
112
- }
113
- function computeSuiteId(suite, parentSuiteId) {
114
- return stableObjectHash({
115
- parentSuiteId: parentSuiteId ?? "",
116
- type: suite.type,
117
- file: suite.location?.file ?? "",
118
- title: suite.title
119
- });
120
- }
121
- function computeTestId(test, suiteId) {
122
- return stableObjectHash({
123
- suiteId,
124
- file: test.location?.file ?? "",
125
- title: test.title
126
- });
127
- }
128
-
129
- // src/stripAnsi.ts
130
- var ansiRegex = new RegExp("[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))", "g");
131
- function stripAnsi(str) {
132
- return str.replace(ansiRegex, "");
133
- }
134
-
135
- // src/visitTests.ts
136
- function visitTests(report, testVisitor) {
137
- function visitSuite(suite, parents) {
138
- parents.push(suite);
139
- for (const test of suite.tests ?? [])
140
- testVisitor(test, parents);
141
- for (const childSuite of suite.suites ?? [])
142
- visitSuite(childSuite, parents);
143
- parents.pop();
144
- }
145
- for (const test of report.tests ?? [])
146
- testVisitor(test, []);
147
- for (const suite of report.suites)
148
- visitSuite(suite, []);
149
- }
2
+ import * as ReportUtils from "./reportUtilsBrowser.js";
150
3
  export {
151
4
  FlakinessReport,
152
- reportUtilsBrowser_exports as ReportUtils
5
+ ReportUtils
153
6
  };
154
7
  //# sourceMappingURL=browser.js.map
package/lib/ciUtils.js CHANGED
@@ -1,4 +1,3 @@
1
- // src/ciUtils.ts
2
1
  var CIUtils;
3
2
  ((CIUtils2) => {
4
3
  function runUrl() {
@@ -1,110 +1,6 @@
1
- // src/createEnvironment.ts
2
1
  import fs from "fs";
3
2
  import os from "os";
4
-
5
- // src/_internalUtils.ts
6
- import { spawnSync } from "child_process";
7
- import http from "http";
8
- import https from "https";
9
- import util from "util";
10
- import zlib from "zlib";
11
- var asyncBrotliCompress = util.promisify(zlib.brotliCompress);
12
- var FLAKINESS_DBG = !!process.env.FLAKINESS_DBG;
13
- function errorText(error) {
14
- return FLAKINESS_DBG ? error.stack : error.message;
15
- }
16
- async function retryWithBackoff(job, backoff = []) {
17
- for (const timeout of backoff) {
18
- try {
19
- return await job();
20
- } catch (e) {
21
- if (e instanceof AggregateError)
22
- console.error(`[flakiness.io err]`, errorText(e.errors[0]));
23
- else if (e instanceof Error)
24
- console.error(`[flakiness.io err]`, errorText(e));
25
- else
26
- console.error(`[flakiness.io err]`, e);
27
- await new Promise((x) => setTimeout(x, timeout));
28
- }
29
- }
30
- return await job();
31
- }
32
- var httpUtils;
33
- ((httpUtils2) => {
34
- function createRequest({ url, method = "get", headers = {} }) {
35
- let resolve;
36
- let reject;
37
- const responseDataPromise = new Promise((a, b) => {
38
- resolve = a;
39
- reject = b;
40
- });
41
- const protocol = url.startsWith("https") ? https : http;
42
- headers = Object.fromEntries(Object.entries(headers).filter(([key, value]) => value !== void 0));
43
- const request = protocol.request(url, { method, headers }, (res) => {
44
- const chunks = [];
45
- res.on("data", (chunk) => chunks.push(chunk));
46
- res.on("end", () => {
47
- if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300)
48
- resolve(Buffer.concat(chunks));
49
- else
50
- reject(new Error(`Request to ${url} failed with ${res.statusCode}`));
51
- });
52
- res.on("error", (error) => reject(error));
53
- });
54
- request.on("error", reject);
55
- return { request, responseDataPromise };
56
- }
57
- httpUtils2.createRequest = createRequest;
58
- async function getBuffer(url, backoff) {
59
- return await retryWithBackoff(async () => {
60
- const { request, responseDataPromise } = createRequest({ url });
61
- request.end();
62
- return await responseDataPromise;
63
- }, backoff);
64
- }
65
- httpUtils2.getBuffer = getBuffer;
66
- async function getText(url, backoff) {
67
- const buffer = await getBuffer(url, backoff);
68
- return buffer.toString("utf-8");
69
- }
70
- httpUtils2.getText = getText;
71
- async function getJSON(url) {
72
- return JSON.parse(await getText(url));
73
- }
74
- httpUtils2.getJSON = getJSON;
75
- async function postText(url, text, backoff) {
76
- const headers = {
77
- "Content-Type": "application/json",
78
- "Content-Length": Buffer.byteLength(text) + ""
79
- };
80
- return await retryWithBackoff(async () => {
81
- const { request, responseDataPromise } = createRequest({ url, headers, method: "post" });
82
- request.write(text);
83
- request.end();
84
- return await responseDataPromise;
85
- }, backoff);
86
- }
87
- httpUtils2.postText = postText;
88
- async function postJSON(url, json, backoff) {
89
- const buffer = await postText(url, JSON.stringify(json), backoff);
90
- return JSON.parse(buffer.toString("utf-8"));
91
- }
92
- httpUtils2.postJSON = postJSON;
93
- })(httpUtils || (httpUtils = {}));
94
- function shell(command, args, options) {
95
- try {
96
- const result = spawnSync(command, args, { encoding: "utf-8", ...options });
97
- if (result.status !== 0) {
98
- return void 0;
99
- }
100
- return result.stdout.trim();
101
- } catch (e) {
102
- console.error(e);
103
- return void 0;
104
- }
105
- }
106
-
107
- // src/createEnvironment.ts
3
+ import { shell } from "./_internalUtils.js";
108
4
  function readLinuxOSRelease() {
109
5
  const osReleaseText = fs.readFileSync("/etc/os-release", "utf-8");
110
6
  return new Map(osReleaseText.toLowerCase().split("\n").filter((line) => line.includes("=")).map((line) => {
@@ -1,24 +1,6 @@
1
- // src/createTestStepSnippets.ts
2
1
  import { codeFrameColumns } from "@babel/code-frame";
3
2
  import fs from "fs";
4
-
5
- // src/visitTests.ts
6
- function visitTests(report, testVisitor) {
7
- function visitSuite(suite, parents) {
8
- parents.push(suite);
9
- for (const test of suite.tests ?? [])
10
- testVisitor(test, parents);
11
- for (const childSuite of suite.suites ?? [])
12
- visitSuite(childSuite, parents);
13
- parents.pop();
14
- }
15
- for (const test of report.tests ?? [])
16
- testVisitor(test, []);
17
- for (const suite of report.suites)
18
- visitSuite(suite, []);
19
- }
20
-
21
- // src/createTestStepSnippets.ts
3
+ import { visitTests } from "./visitTests.js";
22
4
  function createTestStepSnippetsInplace(worktree, report) {
23
5
  const allSteps = /* @__PURE__ */ new Map();
24
6
  visitTests(report, (test) => {