@flakiness/sdk 3.3.0 → 3.4.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/index.js
CHANGED
|
@@ -150,21 +150,11 @@ async function compressTextAsync(text) {
|
|
|
150
150
|
}
|
|
151
151
|
});
|
|
152
152
|
}
|
|
153
|
-
var FLAKINESS_DBG = !!process.env.FLAKINESS_DBG;
|
|
154
|
-
function errorText(error) {
|
|
155
|
-
return FLAKINESS_DBG ? error.stack : error.message;
|
|
156
|
-
}
|
|
157
153
|
async function retryWithBackoff(job, backoff = []) {
|
|
158
154
|
for (const timeout of backoff) {
|
|
159
155
|
try {
|
|
160
156
|
return await job();
|
|
161
157
|
} catch (e) {
|
|
162
|
-
if (e instanceof AggregateError)
|
|
163
|
-
console.error(`[flakiness.io err]`, errorText(e.errors[0]));
|
|
164
|
-
else if (e instanceof Error)
|
|
165
|
-
console.error(`[flakiness.io err]`, errorText(e));
|
|
166
|
-
else
|
|
167
|
-
console.error(`[flakiness.io err]`, e);
|
|
168
158
|
await new Promise((x) => setTimeout(x, timeout));
|
|
169
159
|
}
|
|
170
160
|
}
|
|
@@ -276,6 +266,7 @@ var GitWorktree = class _GitWorktree {
|
|
|
276
266
|
this._gitRoot = _gitRoot;
|
|
277
267
|
this._posixGitRoot = toPosixAbsolutePath(this._gitRoot);
|
|
278
268
|
}
|
|
269
|
+
_gitRoot;
|
|
279
270
|
/**
|
|
280
271
|
* Initializes a GitWorktree for any path inside a git repository and resolves the
|
|
281
272
|
* HEAD commit id in a single call.
|
|
@@ -502,6 +493,8 @@ var GithubOIDC = class _GithubOIDC {
|
|
|
502
493
|
this._requestUrl = _requestUrl;
|
|
503
494
|
this._requestToken = _requestToken;
|
|
504
495
|
}
|
|
496
|
+
_requestUrl;
|
|
497
|
+
_requestToken;
|
|
505
498
|
/**
|
|
506
499
|
* Creates a GithubOIDC instance from GitHub Actions environment variables.
|
|
507
500
|
*
|
|
@@ -1099,10 +1092,17 @@ async function fetchTestDurations(report, options) {
|
|
|
1099
1092
|
const githubOIDC = GithubOIDC.initializeFromEnv();
|
|
1100
1093
|
if (!flakinessAccessToken && githubOIDC && report.flakinessProject)
|
|
1101
1094
|
flakinessAccessToken = await githubOIDC.createFlakinessAccessToken(report.flakinessProject);
|
|
1102
|
-
if (!flakinessAccessToken)
|
|
1103
|
-
throw new Error("No Flakiness access token available (set FLAKINESS_ACCESS_TOKEN, pass `flakinessAccessToken`, or run in GitHub Actions with `id-token: write` and a configured `flakinessProject`)");
|
|
1104
1095
|
const flakinessEndpoint = options?.flakinessEndpoint ?? process.env["FLAKINESS_ENDPOINT"] ?? "https://flakiness.io";
|
|
1105
|
-
|
|
1096
|
+
let orgSlug;
|
|
1097
|
+
let projectSlug;
|
|
1098
|
+
if (!flakinessAccessToken) {
|
|
1099
|
+
if (!report.flakinessProject)
|
|
1100
|
+
throw new Error("Cannot fetch test durations: no Flakiness access token, and `report.flakinessProject` is unset so the project cannot be identified. Set FLAKINESS_ACCESS_TOKEN, pass `flakinessAccessToken`, or set `flakinessProject` (anonymous, public projects only).");
|
|
1101
|
+
[orgSlug, projectSlug] = report.flakinessProject.split("/");
|
|
1102
|
+
if (!orgSlug || !projectSlug)
|
|
1103
|
+
throw new Error(`Cannot fetch test durations: \`report.flakinessProject\` must be in "org/project" format, got ${JSON.stringify(report.flakinessProject)}.`);
|
|
1104
|
+
}
|
|
1105
|
+
const fetcher = new TestDurationsFetcher(report, { flakinessAccessToken, flakinessEndpoint, orgSlug, projectSlug });
|
|
1106
1106
|
return await fetcher.fetch();
|
|
1107
1107
|
}
|
|
1108
1108
|
var TestDurationsFetcher = class {
|
|
@@ -1115,12 +1115,12 @@ var TestDurationsFetcher = class {
|
|
|
1115
1115
|
async _api(pathname, token, body) {
|
|
1116
1116
|
const url = new URL3(this._options.flakinessEndpoint);
|
|
1117
1117
|
url.pathname = pathname;
|
|
1118
|
+
const headers = { "Content-Type": "application/json" };
|
|
1119
|
+
if (token)
|
|
1120
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
1118
1121
|
return await getJSON(url, {
|
|
1119
1122
|
method: "POST",
|
|
1120
|
-
headers
|
|
1121
|
-
"Authorization": `Bearer ${token}`,
|
|
1122
|
-
"Content-Type": "application/json"
|
|
1123
|
-
},
|
|
1123
|
+
headers,
|
|
1124
1124
|
body: body ? JSON.stringify(body) : void 0
|
|
1125
1125
|
});
|
|
1126
1126
|
}
|
|
@@ -1134,7 +1134,15 @@ var TestDurationsFetcher = class {
|
|
|
1134
1134
|
const createResponse = await this._api(
|
|
1135
1135
|
"/api/testDurations/create",
|
|
1136
1136
|
this._options.flakinessAccessToken,
|
|
1137
|
-
{
|
|
1137
|
+
{
|
|
1138
|
+
commitId: this._report.commitId,
|
|
1139
|
+
shardGroupKey,
|
|
1140
|
+
// With a token the server resolves the project from it. Anonymous
|
|
1141
|
+
// callers must name the project explicitly; these are undefined (and so
|
|
1142
|
+
// omitted from the JSON) in the authenticated path.
|
|
1143
|
+
orgSlug: this._options.orgSlug,
|
|
1144
|
+
projectSlug: this._options.projectSlug
|
|
1145
|
+
}
|
|
1138
1146
|
);
|
|
1139
1147
|
await this._uploadReport(JSON.stringify(this._report), createResponse.uploadUrl);
|
|
1140
1148
|
const submitResponse = await this._api(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flakiness/sdk",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.4.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -28,16 +28,16 @@
|
|
|
28
28
|
"node": "^20.17.0 || >=22.9.0"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@flakiness/flakiness-report": "
|
|
32
|
-
"@flakiness/playwright": "^1.
|
|
33
|
-
"@playwright/test": "^1.
|
|
34
|
-
"@types/debug": "^4.1.
|
|
35
|
-
"@types/node": "^25.
|
|
31
|
+
"@flakiness/flakiness-report": "0.35.0",
|
|
32
|
+
"@flakiness/playwright": "^1.14.0",
|
|
33
|
+
"@playwright/test": "^1.61.0",
|
|
34
|
+
"@types/debug": "^4.1.13",
|
|
35
|
+
"@types/node": "^25.9.4",
|
|
36
36
|
"@types/which": "^3.0.4",
|
|
37
|
-
"esbuild": "^0.
|
|
37
|
+
"esbuild": "^0.28.1",
|
|
38
38
|
"kubik": "^0.24.0",
|
|
39
|
-
"tsx": "^4.
|
|
40
|
-
"typescript": "^5.
|
|
39
|
+
"tsx": "^4.22.4",
|
|
40
|
+
"typescript": "^5.9.3"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
43
|
"@flakiness/flakiness-report": ">=0.26.0 <1.0.0"
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
"debug": "^4.4.3",
|
|
47
47
|
"open": "^10.2.0",
|
|
48
48
|
"stable-hash": "^0.0.6",
|
|
49
|
-
"which": "^
|
|
50
|
-
"zod": "^4.3
|
|
49
|
+
"which": "^7.0.0",
|
|
50
|
+
"zod": "^4.4.3"
|
|
51
51
|
},
|
|
52
52
|
"scripts": {
|
|
53
53
|
"minor": "./version.mjs minor",
|
|
@@ -4,7 +4,6 @@ export declare function compressTextAsync(text: string | Buffer): Promise<Buffer
|
|
|
4
4
|
export type Brand<T, Brand extends string> = T & {
|
|
5
5
|
readonly [B in Brand as `__${B}_brand`]: never;
|
|
6
6
|
};
|
|
7
|
-
export declare function errorText(error: Error): string | undefined;
|
|
8
7
|
export declare function retryWithBackoff<T>(job: () => Promise<T>, backoff?: number[]): Promise<T>;
|
|
9
8
|
export declare const HTTP_BACKOFF: number[];
|
|
10
9
|
export declare function getJSON<T>(input: RequestInfo | URL, init?: RequestInit, backoff?: number[]): Promise<T>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_internalUtils.d.ts","sourceRoot":"","sources":["../../src/_internalUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,kCAAkC,EAAE,MAAM,eAAe,CAAC;AAC9E,OAAO,MAAM,MAAM,QAAQ,CAAC;AAM5B,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQ5E;AAED,MAAM,MAAM,KAAK,CAAC,CAAC,EAAE,KAAK,SAAS,MAAM,IAAI,CAAC,GAAG;IAC/C,QAAQ,EAAE,CAAC,IAAI,KAAK,IAAI,KAAK,CAAC,QAAQ,GAAG,KAAK;CAC/C,CAAC;AAGF,
|
|
1
|
+
{"version":3,"file":"_internalUtils.d.ts","sourceRoot":"","sources":["../../src/_internalUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,kCAAkC,EAAE,MAAM,eAAe,CAAC;AAC9E,OAAO,MAAM,MAAM,QAAQ,CAAC;AAM5B,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQ5E;AAED,MAAM,MAAM,KAAK,CAAC,CAAC,EAAE,KAAK,SAAS,MAAM,IAAI,CAAC,GAAG;IAC/C,QAAQ,EAAE,CAAC,IAAI,KAAK,IAAI,KAAK,CAAC,QAAQ,GAAG,KAAK;CAC/C,CAAC;AAGF,wBAAsB,gBAAgB,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CASnG;AAED,eAAO,MAAM,YAAY,UAAqC,CAAC;AAY/D,wBAAsB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,WAAW,EAAE,OAAO,GAAE,MAAM,EAAiB,GAAG,OAAO,CAAC,CAAC,CAAC,CAK3H;AAED,wBAAsB,SAAS,CAAC,KAAK,EAAE,WAAW,GAAG,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,EAAE,OAAO,GAAE,MAAM,EAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAU9I;AAED,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,kCAAkC,sBAWnG;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,UAAU,UAI/C;AAED,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAc1D;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAczC"}
|
|
@@ -16,9 +16,10 @@ export type FetchTestDurationsOptions = {
|
|
|
16
16
|
* Access token for authenticating with the Flakiness.io platform.
|
|
17
17
|
*
|
|
18
18
|
* Defaults to the `FLAKINESS_ACCESS_TOKEN` environment variable. If no token is provided
|
|
19
|
-
* through this option or the environment variable, the function
|
|
20
|
-
*
|
|
21
|
-
* to be
|
|
19
|
+
* through this option or the environment variable, the function attempts GitHub Actions OIDC
|
|
20
|
+
* when running in GitHub Actions (requires `report.flakinessProject` to be set and the project
|
|
21
|
+
* to be bound to the repository). If no token can be obtained, durations are fetched anonymously
|
|
22
|
+
* using `report.flakinessProject`, which the server only allows for public projects.
|
|
22
23
|
*
|
|
23
24
|
* @example 'flakiness-io-1234567890abcdef...'
|
|
24
25
|
*/
|
|
@@ -32,7 +33,8 @@ export type FetchTestDurationsOptions = {
|
|
|
32
33
|
* finishes at roughly the same time.
|
|
33
34
|
*
|
|
34
35
|
* The function performs the following steps:
|
|
35
|
-
* 1.
|
|
36
|
+
* 1. Resolves credentials: an access token, GitHub Actions OIDC, or anonymous access
|
|
37
|
+
* for public projects.
|
|
36
38
|
* 2. Computes a shard-group key from the report so that all shards of the same run
|
|
37
39
|
* fetch an identical set of timings.
|
|
38
40
|
* 3. Uploads the (compressed) report so the platform knows which tests to time.
|
|
@@ -45,14 +47,18 @@ export type FetchTestDurationsOptions = {
|
|
|
45
47
|
* 1. **Access token** — provided via `flakinessAccessToken` option or `FLAKINESS_ACCESS_TOKEN` env var.
|
|
46
48
|
* 2. **GitHub Actions OIDC** — when running in GitHub Actions with no access token. This requires
|
|
47
49
|
* `report.flakinessProject` to be set and the project to be bound to the GitHub repository.
|
|
50
|
+
* 3. **Anonymous** — when no token can be obtained but `report.flakinessProject` is set. The request
|
|
51
|
+
* names the project via that field and sends no credentials. The server only honors this for public
|
|
52
|
+
* projects, which covers pull requests from forks: GitHub denies them both repository secrets and an
|
|
53
|
+
* OIDC token. Private projects are rejected by the server.
|
|
48
54
|
*
|
|
49
55
|
* @param {FlakinessReport.Report} report - The report describing the tests to fetch durations for.
|
|
50
56
|
* @param {FetchTestDurationsOptions} options - Optional configuration object.
|
|
51
57
|
*
|
|
52
58
|
* @returns {Promise<FlakinessReport.Report>} A report enriched with historical test durations.
|
|
53
59
|
*
|
|
54
|
-
* @throws {Error} If
|
|
55
|
-
* ready within the polling timeout.
|
|
60
|
+
* @throws {Error} If the project cannot be identified (no access token and no `report.flakinessProject`),
|
|
61
|
+
* any API call fails, or the durations are not ready within the polling timeout.
|
|
56
62
|
*
|
|
57
63
|
* @example
|
|
58
64
|
* ```typescript
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetchTestDurations.d.ts","sourceRoot":"","sources":["../../src/fetchTestDurations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"fetchTestDurations.d.ts","sourceRoot":"","sources":["../../src/fetchTestDurations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAgB9D;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACtC;;;;;;;OAOG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B;;;;;;;;;;OAUG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B,CAAA;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,eAAe,CAAC,MAAM,EAC9B,OAAO,CAAC,EAAE,yBAAyB,GAClC,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,CA0BjC"}
|