@flakiness/sdk 2.6.0 → 3.0.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/README.md CHANGED
@@ -27,13 +27,16 @@ import {
27
27
  } from '@flakiness/sdk';
28
28
 
29
29
  // Initialize git worktree and environment
30
- const worktree = GitWorktree.create(process.cwd());
30
+ const result = GitWorktree.initialize(process.cwd());
31
+ if (!result.ok)
32
+ throw new Error(result.error);
33
+ const { worktree, commitId } = result;
31
34
  const env = ReportUtils.createEnvironment({ name: 'CI' });
32
35
 
33
36
  // Create a simple test report
34
37
  const report: FlakinessReport.Report = {
35
38
  category: 'testreport',
36
- commitId: worktree.headCommitId(),
39
+ commitId,
37
40
  title: process.env.FLAKINESS_TITLE,
38
41
  url: CIUtils.runUrl(),
39
42
  environments: [env],
package/lib/browser.js CHANGED
@@ -33,6 +33,7 @@ function normalizeReport(report) {
33
33
  return {
34
34
  ...step,
35
35
  duration: step.duration === 0 ? void 0 : step.duration,
36
+ attachments: step.attachments && step.attachments.length ? step.attachments : void 0,
36
37
  steps: step.steps && step.steps.length ? step.steps.map(cleanupTestStep) : void 0
37
38
  };
38
39
  }
package/lib/index.js CHANGED
@@ -251,29 +251,48 @@ var GitWorktree = class _GitWorktree {
251
251
  this._posixGitRoot = toPosixAbsolutePath(this._gitRoot);
252
252
  }
253
253
  /**
254
- * Creates a GitWorktree instance from any path inside a git repository.
254
+ * Initializes a GitWorktree for any path inside a git repository and resolves the
255
+ * HEAD commit id in a single call.
255
256
  *
256
- * @param {string} somePathInsideGitRepo - Any path (file or directory) within a git repository.
257
- * Can be absolute or relative. The function will locate the git root directory.
257
+ * Unlike a constructor, this method never throws callers check `result.ok` and bail
258
+ * out early, after which TypeScript narrows `worktree` and `commitId` on the result.
258
259
  *
259
- * @returns {GitWorktree} A new GitWorktree instance bound to the discovered git root.
260
+ * @param {string} somePathInsideGitRepo - Any path (file or directory) within a git
261
+ * repository. Can be absolute or relative. The function will locate the git root.
260
262
  *
261
- * @throws {Error} Throws if the path is not inside a git repository or if git commands fail.
263
+ * @returns {GitWorktreeInitResult} `{ ok: true, worktree, commitId }` on success, or
264
+ * `{ ok: false, error }` describing what went wrong.
262
265
  *
263
266
  * @example
264
267
  * ```typescript
265
- * const worktree = GitWorktree.create('./src/my-test.ts');
266
- * const gitRoot = worktree.rootPath();
268
+ * const result = GitWorktree.initialize('./src/my-test.ts');
269
+ * if (!result.ok) {
270
+ * console.error(result.error);
271
+ * return;
272
+ * }
273
+ * // result.worktree and result.commitId are narrowed to non-undefined here.
267
274
  * ```
268
275
  */
269
- static create(somePathInsideGitRepo) {
276
+ static initialize(somePathInsideGitRepo) {
270
277
  const root = shell(`git`, ["rev-parse", "--show-toplevel"], {
271
278
  cwd: somePathInsideGitRepo,
272
279
  encoding: "utf-8",
273
280
  env: GIT_SAFE_ENV
274
281
  });
275
- assert(root, `FAILED: git rev-parse --show-toplevel HEAD @ ${somePathInsideGitRepo}`);
276
- return new _GitWorktree(root);
282
+ if (!root)
283
+ return { ok: false, error: `FAILED: git rev-parse --show-toplevel @ ${somePathInsideGitRepo}` };
284
+ const sha = shell(`git`, ["rev-parse", "HEAD"], {
285
+ cwd: root,
286
+ encoding: "utf-8",
287
+ env: GIT_SAFE_ENV
288
+ });
289
+ if (!sha)
290
+ return { ok: false, error: `FAILED: git rev-parse HEAD @ ${root}` };
291
+ return {
292
+ ok: true,
293
+ worktree: new _GitWorktree(root),
294
+ commitId: sha.trim()
295
+ };
277
296
  }
278
297
  _posixGitRoot;
279
298
  /**
@@ -292,28 +311,6 @@ var GitWorktree = class _GitWorktree {
292
311
  rootPath() {
293
312
  return this._gitRoot;
294
313
  }
295
- /**
296
- * Returns the commit ID (SHA-1 hash) of the current HEAD commit.
297
- *
298
- * @returns {FlakinessReport.CommitId} Full 40-character commit hash of the HEAD commit.
299
- *
300
- * @throws {Error} Throws if git command fails or repository is in an invalid state.
301
- *
302
- * @example
303
- * ```typescript
304
- * const commitId = worktree.headCommitId();
305
- * // Returns: 'a1b2c3d4e5f6...' (40-character SHA-1)
306
- * ```
307
- */
308
- headCommitId() {
309
- const sha = shell(`git`, ["rev-parse", "HEAD"], {
310
- cwd: this._gitRoot,
311
- encoding: "utf-8",
312
- env: GIT_SAFE_ENV
313
- });
314
- assert(sha, `FAILED: git rev-parse HEAD @ ${this._gitRoot}`);
315
- return sha.trim();
316
- }
317
314
  /**
318
315
  * Converts a native absolute path to a git-relative POSIX path.
319
316
  *
@@ -703,6 +700,7 @@ function normalizeReport(report) {
703
700
  return {
704
701
  ...step,
705
702
  duration: step.duration === 0 ? void 0 : step.duration,
703
+ attachments: step.attachments && step.attachments.length ? step.attachments : void 0,
706
704
  steps: step.steps && step.steps.length ? step.steps.map(cleanupTestStep) : void 0
707
705
  };
708
706
  }
@@ -1101,21 +1099,31 @@ async function readReport(reportFolder) {
1101
1099
  const filenameToPath = new Map(attachmentFiles.map((file) => [path.basename(file), file]));
1102
1100
  const attachmentIdToPath = /* @__PURE__ */ new Map();
1103
1101
  const missingAttachments = /* @__PURE__ */ new Map();
1102
+ const visitAttachment = (attachment) => {
1103
+ const attachmentPath = filenameToPath.get(attachment.id);
1104
+ if (!attachmentPath) {
1105
+ missingAttachments.set(attachment.id, attachment);
1106
+ } else {
1107
+ attachmentIdToPath.set(attachment.id, {
1108
+ contentType: attachment.contentType,
1109
+ id: attachment.id,
1110
+ path: attachmentPath,
1111
+ type: "file"
1112
+ });
1113
+ }
1114
+ };
1115
+ const visitStep = (step) => {
1116
+ for (const attachment of step.attachments ?? [])
1117
+ visitAttachment(attachment);
1118
+ for (const childStep of step.steps ?? [])
1119
+ visitStep(childStep);
1120
+ };
1104
1121
  visitTests(report, (test) => {
1105
1122
  for (const attempt of test.attempts) {
1106
- for (const attachment of attempt.attachments ?? []) {
1107
- const attachmentPath = filenameToPath.get(attachment.id);
1108
- if (!attachmentPath) {
1109
- missingAttachments.set(attachment.id, attachment);
1110
- } else {
1111
- attachmentIdToPath.set(attachment.id, {
1112
- contentType: attachment.contentType,
1113
- id: attachment.id,
1114
- path: attachmentPath,
1115
- type: "file"
1116
- });
1117
- }
1118
- }
1123
+ for (const attachment of attempt.attachments ?? [])
1124
+ visitAttachment(attachment);
1125
+ for (const step of attempt.steps ?? [])
1126
+ visitStep(step);
1119
1127
  }
1120
1128
  });
1121
1129
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flakiness/sdk",
3
- "version": "2.6.0",
3
+ "version": "3.0.0",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
@@ -28,7 +28,7 @@
28
28
  "node": "^20.17.0 || >=22.9.0"
29
29
  },
30
30
  "devDependencies": {
31
- "@flakiness/flakiness-report": "^0.28.0",
31
+ "@flakiness/flakiness-report": "^0.31.0",
32
32
  "@flakiness/playwright": "^1.3.3",
33
33
  "@playwright/test": "^1.58.2",
34
34
  "@types/debug": "^4.1.12",
@@ -17,6 +17,18 @@ export type GitCommit = {
17
17
  /** Array of parent commit IDs (empty for initial commit, typically one for normal commits, multiple for merges) */
18
18
  parents: FlakinessReport.CommitId[];
19
19
  };
20
+ /**
21
+ * Result of {@link GitWorktree.initialize}. A tagged discriminated union:
22
+ * check `ok` and TypeScript narrows the rest of the fields.
23
+ */
24
+ export type GitWorktreeInitResult = {
25
+ ok: true;
26
+ worktree: GitWorktree;
27
+ commitId: FlakinessReport.CommitId;
28
+ } | {
29
+ ok: false;
30
+ error: string;
31
+ };
20
32
  /**
21
33
  * Utilities for working with git repositories and converting between git-relative paths
22
34
  * and absolute native paths. Essential for creating Flakiness Reports where all paths
@@ -25,22 +37,29 @@ export type GitCommit = {
25
37
  export declare class GitWorktree {
26
38
  private _gitRoot;
27
39
  /**
28
- * Creates a GitWorktree instance from any path inside a git repository.
40
+ * Initializes a GitWorktree for any path inside a git repository and resolves the
41
+ * HEAD commit id in a single call.
29
42
  *
30
- * @param {string} somePathInsideGitRepo - Any path (file or directory) within a git repository.
31
- * Can be absolute or relative. The function will locate the git root directory.
43
+ * Unlike a constructor, this method never throws callers check `result.ok` and bail
44
+ * out early, after which TypeScript narrows `worktree` and `commitId` on the result.
32
45
  *
33
- * @returns {GitWorktree} A new GitWorktree instance bound to the discovered git root.
46
+ * @param {string} somePathInsideGitRepo - Any path (file or directory) within a git
47
+ * repository. Can be absolute or relative. The function will locate the git root.
34
48
  *
35
- * @throws {Error} Throws if the path is not inside a git repository or if git commands fail.
49
+ * @returns {GitWorktreeInitResult} `{ ok: true, worktree, commitId }` on success, or
50
+ * `{ ok: false, error }` describing what went wrong.
36
51
  *
37
52
  * @example
38
53
  * ```typescript
39
- * const worktree = GitWorktree.create('./src/my-test.ts');
40
- * const gitRoot = worktree.rootPath();
54
+ * const result = GitWorktree.initialize('./src/my-test.ts');
55
+ * if (!result.ok) {
56
+ * console.error(result.error);
57
+ * return;
58
+ * }
59
+ * // result.worktree and result.commitId are narrowed to non-undefined here.
41
60
  * ```
42
61
  */
43
- static create(somePathInsideGitRepo: string): GitWorktree;
62
+ static initialize(somePathInsideGitRepo: string): GitWorktreeInitResult;
44
63
  private _posixGitRoot;
45
64
  constructor(_gitRoot: string);
46
65
  /**
@@ -57,20 +76,6 @@ export declare class GitWorktree {
57
76
  * ```
58
77
  */
59
78
  rootPath(): string;
60
- /**
61
- * Returns the commit ID (SHA-1 hash) of the current HEAD commit.
62
- *
63
- * @returns {FlakinessReport.CommitId} Full 40-character commit hash of the HEAD commit.
64
- *
65
- * @throws {Error} Throws if git command fails or repository is in an invalid state.
66
- *
67
- * @example
68
- * ```typescript
69
- * const commitId = worktree.headCommitId();
70
- * // Returns: 'a1b2c3d4e5f6...' (40-character SHA-1)
71
- * ```
72
- */
73
- headCommitId(): FlakinessReport.CommitId;
74
79
  /**
75
80
  * Converts a native absolute path to a git-relative POSIX path.
76
81
  *
@@ -1 +1 @@
1
- {"version":3,"file":"gitWorktree.d.ts","sourceRoot":"","sources":["../../src/gitWorktree.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAwB9D;;;;;GAKG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB,8CAA8C;IAC9C,QAAQ,EAAE,eAAe,CAAC,QAAQ,CAAC;IACnC,wDAAwD;IACxD,SAAS,EAAE,eAAe,CAAC,eAAe,CAAC;IAC3C,yCAAyC;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,gCAAgC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mHAAmH;IACnH,OAAO,EAAE,eAAe,CAAC,QAAQ,EAAE,CAAC;CACrC,CAAA;AAyCD;;;;GAIG;AACH,qBAAa,WAAW;IA6BV,OAAO,CAAC,QAAQ;IA5B5B;;;;;;;;;;;;;;;OAeG;IACH,MAAM,CAAC,MAAM,CAAC,qBAAqB,EAAE,MAAM;IAU3C,OAAO,CAAC,aAAa,CAAoB;gBAErB,QAAQ,EAAE,MAAM;IAIpC;;;;;;;;;;;;OAYG;IACH,QAAQ,IAAI,MAAM;IAIlB;;;;;;;;;;;;OAYG;IACH,YAAY,IAAI,eAAe,CAAC,QAAQ;IAUxC;;;;;;;;;;;;;;;;;;OAkBG;IACH,OAAO,CAAC,YAAY,EAAE,MAAM,GAAG,eAAe,CAAC,WAAW;IAI1D;;;;;;;;;;;;;;;;;;OAkBG;IACH,YAAY,CAAC,YAAY,EAAE,eAAe,CAAC,WAAW,GAAG,MAAM;IAI/D;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACG,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;CAGvD"}
1
+ {"version":3,"file":"gitWorktree.d.ts","sourceRoot":"","sources":["../../src/gitWorktree.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAwB9D;;;;;GAKG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB,8CAA8C;IAC9C,QAAQ,EAAE,eAAe,CAAC,QAAQ,CAAC;IACnC,wDAAwD;IACxD,SAAS,EAAE,eAAe,CAAC,eAAe,CAAC;IAC3C,yCAAyC;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,gCAAgC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mHAAmH;IACnH,OAAO,EAAE,eAAe,CAAC,QAAQ,EAAE,CAAC;CACrC,CAAA;AAyCD;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAC7B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE,eAAe,CAAC,QAAQ,CAAA;CAAE,GACvE;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjC;;;;GAIG;AACH,qBAAa,WAAW;IAkDV,OAAO,CAAC,QAAQ;IAjD5B;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,MAAM,CAAC,UAAU,CAAC,qBAAqB,EAAE,MAAM,GAAG,qBAAqB;IAwBvE,OAAO,CAAC,aAAa,CAAoB;gBAErB,QAAQ,EAAE,MAAM;IAIpC;;;;;;;;;;;;OAYG;IACH,QAAQ,IAAI,MAAM;IAIlB;;;;;;;;;;;;;;;;;;OAkBG;IACH,OAAO,CAAC,YAAY,EAAE,MAAM,GAAG,eAAe,CAAC,WAAW;IAI1D;;;;;;;;;;;;;;;;;;OAkBG;IACH,YAAY,CAAC,YAAY,EAAE,eAAe,CAAC,WAAW,GAAG,MAAM;IAI/D;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACG,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;CAGvD"}
@@ -1,6 +1,6 @@
1
1
  export { CIUtils } from './ciUtils.js';
2
2
  export { CPUUtilization } from './cpuUtilization.js';
3
- export { GitWorktree } from './gitWorktree.js';
3
+ export { GitWorktree, type GitWorktreeInitResult } from './gitWorktree.js';
4
4
  export { RAMUtilization } from './ramUtilization.js';
5
5
  export { GithubOIDC } from './githubOIDC.js';
6
6
  export * as ReportUtils from './reportUtils.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,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,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAC;AAGhD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,KAAK,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAC3E,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAC;AAGhD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
@@ -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;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,CAAC,MAAM,GAAG,eAAe,CAAC,MAAM,CAmDtF"}
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,CAoDtF"}
@@ -1 +1 @@
1
- {"version":3,"file":"readReport.d.ts","sourceRoot":"","sources":["../../src/readReport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAG9D,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAsB,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9D,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC;IAC/B,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,kBAAkB,EAAE,eAAe,CAAC,UAAU,EAAE,CAAC;CAClD,CAAC,CA0CD"}
1
+ {"version":3,"file":"readReport.d.ts","sourceRoot":"","sources":["../../src/readReport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAG9D,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAsB,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9D,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC;IAC/B,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,kBAAkB,EAAE,eAAe,CAAC,UAAU,EAAE,CAAC;CAClD,CAAC,CAoDD"}