@flakiness/sdk
Advanced tools
| import { FlakinessReport } from '@flakiness/flakiness-report'; | ||
| import { FileAttachment } from './uploadReport.js'; | ||
| /** | ||
| * Reads a Flakiness report and its attachments from a folder on disk. | ||
| * | ||
| * This function reads a Flakiness report that was previously written to disk using `writeReport()`. | ||
| * It parses the `report.json` file and locates all attachment files referenced in the report. | ||
| * | ||
| * The function expects the report folder to follow the standard Flakiness report structure: | ||
| * - `report.json` - The main report file containing test results and metadata | ||
| * - `attachments/` - Directory containing all attachment files, named by their ID | ||
| * | ||
| * @param {string} reportFolder - Absolute or relative path to the folder containing the Flakiness | ||
| * report. The folder must contain a `report.json` file. Attachments are expected to be in the | ||
| * `attachments/` subdirectory, but the function will work even if the attachments directory | ||
| * doesn't exist (all attachments will be reported as missing). | ||
| * | ||
| * @returns {Promise<{report: FlakinessReport.Report, attachments: FileAttachment[], missingAttachments: FlakinessReport.Attachment[]}>} | ||
| * Promise that resolves to an object containing: | ||
| * - `report` - The parsed Flakiness report object | ||
| * - `attachments` - Array of `FileAttachment` objects for attachments that were found on disk. | ||
| * Each attachment has: | ||
| * - `type: 'file'` - All returned attachments are file-based | ||
| * - `contentType` - MIME type from the report | ||
| * - `id` - Attachment ID (filename) | ||
| * - `path` - Absolute path to the attachment file | ||
| * - `missingAttachments` - Array of attachment objects from the report that could not be found | ||
| * on disk. This allows callers to detect and handle missing attachments gracefully. | ||
| * | ||
| * @throws {Error} Throws if `report.json` cannot be read, the folder doesn't exist, or JSON parsing fails. | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * const { report, attachments, missingAttachments } = await readReport('./flakiness-report'); | ||
| * | ||
| * if (missingAttachments.length > 0) { | ||
| * console.warn(`Warning: ${missingAttachments.length} attachments are missing`); | ||
| * } | ||
| * | ||
| * // Use the report and attachments | ||
| * await uploadReport(report, attachments); | ||
| * ``` | ||
| */ | ||
| export declare function readReport(reportFolder: string): Promise<{ | ||
| report: FlakinessReport.Report; | ||
| attachments: FileAttachment[]; | ||
| missingAttachments: FlakinessReport.Attachment[]; | ||
| }>; | ||
| //# sourceMappingURL=readReport.d.ts.map |
| {"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"} |
+136
-6
@@ -7,5 +7,136 @@ var __defProp = Object.defineProperty; | ||
| // src/browser.ts | ||
| import { FlakinessReport as FlakinessReport2 } from "@flakiness/flakiness-report"; | ||
| // node_modules/@flakiness/flakiness-report/lib/flakinessReport.js | ||
| var FlakinessReport; | ||
| ((FlakinessReport22) => { | ||
| FlakinessReport22.CATEGORY_PLAYWRIGHT = "playwright"; | ||
| FlakinessReport22.CATEGORY_PYTEST = "pytest"; | ||
| FlakinessReport22.CATEGORY_JUNIT = "junit"; | ||
| })(FlakinessReport || (FlakinessReport = {})); | ||
| // node_modules/@flakiness/flakiness-report/lib/schema.js | ||
| import z from "zod/v4"; | ||
| var Schema; | ||
| ((Schema2) => { | ||
| Schema2.CommitId = z.string().min(40).max(40); | ||
| Schema2.AttachmentId = z.string().min(1).max(1024); | ||
| Schema2.UnixTimestampMS = z.number().min(0); | ||
| Schema2.DurationMS = z.number().min(0); | ||
| Schema2.Number1Based = z.number(); | ||
| Schema2.GitFilePath = z.string().min(0); | ||
| Schema2.Location = z.object({ | ||
| file: Schema2.GitFilePath, | ||
| line: Schema2.Number1Based, | ||
| // Note: Locations for file suites are (0, 0). | ||
| column: Schema2.Number1Based | ||
| }); | ||
| Schema2.TestStatus = z.enum(["passed", "failed", "timedOut", "skipped", "interrupted"]); | ||
| Schema2.Environment = z.object({ | ||
| name: z.string().min(1).max(512), | ||
| systemData: z.object({ | ||
| osName: z.string().optional(), | ||
| osVersion: z.string().optional(), | ||
| osArch: z.string().optional() | ||
| }).optional(), | ||
| metadata: z.any().optional(), | ||
| userSuppliedData: z.any().optional() | ||
| }); | ||
| Schema2.STDIOEntry = z.union([ | ||
| z.object({ text: z.string() }), | ||
| z.object({ buffer: z.string() }) | ||
| ]); | ||
| Schema2.ReportError = z.object({ | ||
| location: Schema2.Location.optional(), | ||
| message: z.string().optional(), | ||
| stack: z.string().optional(), | ||
| snippet: z.string().optional(), | ||
| value: z.string().optional() | ||
| }); | ||
| Schema2.SuiteType = z.enum(["file", "anonymous suite", "suite"]); | ||
| Schema2.TestStep = z.object({ | ||
| title: z.string(), | ||
| duration: Schema2.DurationMS.optional(), | ||
| location: Schema2.Location.optional(), | ||
| snippet: z.string().optional(), | ||
| error: Schema2.ReportError.optional(), | ||
| get steps() { | ||
| return z.array(Schema2.TestStep).optional(); | ||
| } | ||
| }); | ||
| Schema2.Attachment = z.object({ | ||
| name: z.string(), | ||
| contentType: z.string(), | ||
| id: Schema2.AttachmentId | ||
| }); | ||
| Schema2.Annotation = z.object({ | ||
| type: z.string(), | ||
| description: z.string().optional(), | ||
| location: Schema2.Location.optional() | ||
| }); | ||
| Schema2.RunAttempt = z.object({ | ||
| // Index of the environment in the environments array (must be >= 0). | ||
| environmentIdx: z.number().min(0).optional(), | ||
| expectedStatus: Schema2.TestStatus.optional(), | ||
| status: Schema2.TestStatus.optional(), | ||
| startTimestamp: Schema2.UnixTimestampMS, | ||
| duration: Schema2.DurationMS.optional(), | ||
| timeout: Schema2.DurationMS.optional(), | ||
| annotations: z.array(Schema2.Annotation).optional(), | ||
| errors: z.array(Schema2.ReportError).optional(), | ||
| parallelIndex: z.number().optional(), | ||
| steps: z.array(Schema2.TestStep).optional(), | ||
| stdout: z.array(Schema2.STDIOEntry).optional(), | ||
| stderr: z.array(Schema2.STDIOEntry).optional(), | ||
| attachments: z.array(Schema2.Attachment).optional() | ||
| }); | ||
| Schema2.Suite = z.object({ | ||
| type: Schema2.SuiteType, | ||
| title: z.string(), | ||
| location: Schema2.Location.optional(), | ||
| get suites() { | ||
| return z.array(Schema2.Suite).optional(); | ||
| }, | ||
| get tests() { | ||
| return z.array(Schema2.Test).optional(); | ||
| } | ||
| }); | ||
| Schema2.Test = z.object({ | ||
| title: z.string(), | ||
| location: Schema2.Location.optional(), | ||
| tags: z.array(z.string()).optional(), | ||
| attempts: z.array(Schema2.RunAttempt) | ||
| }); | ||
| Schema2.SystemUtilizationSample = z.object({ | ||
| dts: Schema2.DurationMS, | ||
| // Must be between 0 and 100 (inclusive). Can be a rational number. | ||
| cpuUtilization: z.number().min(0).max(100), | ||
| // Must be between 0 and 100 (inclusive). Can be a rational number. | ||
| memoryUtilization: z.number().min(0).max(100) | ||
| }); | ||
| Schema2.SystemUtilization = z.object({ | ||
| totalMemoryBytes: z.number().min(0), | ||
| startTimestamp: Schema2.UnixTimestampMS, | ||
| samples: z.array(Schema2.SystemUtilizationSample) | ||
| }); | ||
| Schema2.UtilizationTelemetry = z.tuple([Schema2.DurationMS, z.number().min(0).max(100)]); | ||
| Schema2.Report = z.object({ | ||
| category: z.string().min(1).max(100), | ||
| commitId: Schema2.CommitId, | ||
| relatedCommitIds: z.array(Schema2.CommitId).optional(), | ||
| configPath: Schema2.GitFilePath.optional(), | ||
| url: z.string().optional(), | ||
| environments: z.array(Schema2.Environment).min(1), | ||
| suites: z.array(Schema2.Suite).optional(), | ||
| tests: z.array(Schema2.Test).optional(), | ||
| unattributedErrors: z.array(Schema2.ReportError).optional(), | ||
| startTimestamp: Schema2.UnixTimestampMS, | ||
| duration: Schema2.DurationMS, | ||
| systemUtilization: z.optional(Schema2.SystemUtilization), | ||
| cpuCount: z.number().min(0).optional(), | ||
| cpuAvg: z.array(Schema2.UtilizationTelemetry).optional(), | ||
| cpuMax: z.array(Schema2.UtilizationTelemetry).optional(), | ||
| ram: z.array(Schema2.UtilizationTelemetry).optional(), | ||
| ramBytes: z.number().min(0).optional() | ||
| }); | ||
| })(Schema || (Schema = {})); | ||
| // src/reportUtilsBrowser.ts | ||
@@ -179,4 +310,3 @@ var reportUtilsBrowser_exports = {}; | ||
| // src/validateReport.ts | ||
| import { Schema } from "@flakiness/flakiness-report"; | ||
| import z from "zod/v4"; | ||
| import z2 from "zod/v4"; | ||
| function validateReport(report) { | ||
@@ -189,3 +319,3 @@ const validation = Schema.Report.safeParse(report); | ||
| const remaining = allIssues.length - shownIssues.length; | ||
| const base = [z.prettifyError(new z.ZodError(shownIssues))]; | ||
| const base = [z2.prettifyError(new z2.ZodError(shownIssues))]; | ||
| if (remaining > 0) | ||
@@ -220,5 +350,5 @@ base.push(`... and ${remaining} more issue${remaining === 1 ? "" : "s"} ...`); | ||
| export { | ||
| FlakinessReport2 as FlakinessReport, | ||
| FlakinessReport, | ||
| reportUtilsBrowser_exports as ReportUtils | ||
| }; | ||
| //# sourceMappingURL=browser.js.map |
+218
-35
@@ -7,5 +7,2 @@ var __defProp = Object.defineProperty; | ||
| // src/index.ts | ||
| import { FlakinessReport as FlakinessReport2, Schema as Schema2 } from "@flakiness/flakiness-report"; | ||
| // src/ciUtils.ts | ||
@@ -782,5 +779,138 @@ var CIUtils; | ||
| // node_modules/@flakiness/flakiness-report/lib/flakinessReport.js | ||
| var FlakinessReport; | ||
| ((FlakinessReport22) => { | ||
| FlakinessReport22.CATEGORY_PLAYWRIGHT = "playwright"; | ||
| FlakinessReport22.CATEGORY_PYTEST = "pytest"; | ||
| FlakinessReport22.CATEGORY_JUNIT = "junit"; | ||
| })(FlakinessReport || (FlakinessReport = {})); | ||
| // node_modules/@flakiness/flakiness-report/lib/schema.js | ||
| import z from "zod/v4"; | ||
| var Schema; | ||
| ((Schema2) => { | ||
| Schema2.CommitId = z.string().min(40).max(40); | ||
| Schema2.AttachmentId = z.string().min(1).max(1024); | ||
| Schema2.UnixTimestampMS = z.number().min(0); | ||
| Schema2.DurationMS = z.number().min(0); | ||
| Schema2.Number1Based = z.number(); | ||
| Schema2.GitFilePath = z.string().min(0); | ||
| Schema2.Location = z.object({ | ||
| file: Schema2.GitFilePath, | ||
| line: Schema2.Number1Based, | ||
| // Note: Locations for file suites are (0, 0). | ||
| column: Schema2.Number1Based | ||
| }); | ||
| Schema2.TestStatus = z.enum(["passed", "failed", "timedOut", "skipped", "interrupted"]); | ||
| Schema2.Environment = z.object({ | ||
| name: z.string().min(1).max(512), | ||
| systemData: z.object({ | ||
| osName: z.string().optional(), | ||
| osVersion: z.string().optional(), | ||
| osArch: z.string().optional() | ||
| }).optional(), | ||
| metadata: z.any().optional(), | ||
| userSuppliedData: z.any().optional() | ||
| }); | ||
| Schema2.STDIOEntry = z.union([ | ||
| z.object({ text: z.string() }), | ||
| z.object({ buffer: z.string() }) | ||
| ]); | ||
| Schema2.ReportError = z.object({ | ||
| location: Schema2.Location.optional(), | ||
| message: z.string().optional(), | ||
| stack: z.string().optional(), | ||
| snippet: z.string().optional(), | ||
| value: z.string().optional() | ||
| }); | ||
| Schema2.SuiteType = z.enum(["file", "anonymous suite", "suite"]); | ||
| Schema2.TestStep = z.object({ | ||
| title: z.string(), | ||
| duration: Schema2.DurationMS.optional(), | ||
| location: Schema2.Location.optional(), | ||
| snippet: z.string().optional(), | ||
| error: Schema2.ReportError.optional(), | ||
| get steps() { | ||
| return z.array(Schema2.TestStep).optional(); | ||
| } | ||
| }); | ||
| Schema2.Attachment = z.object({ | ||
| name: z.string(), | ||
| contentType: z.string(), | ||
| id: Schema2.AttachmentId | ||
| }); | ||
| Schema2.Annotation = z.object({ | ||
| type: z.string(), | ||
| description: z.string().optional(), | ||
| location: Schema2.Location.optional() | ||
| }); | ||
| Schema2.RunAttempt = z.object({ | ||
| // Index of the environment in the environments array (must be >= 0). | ||
| environmentIdx: z.number().min(0).optional(), | ||
| expectedStatus: Schema2.TestStatus.optional(), | ||
| status: Schema2.TestStatus.optional(), | ||
| startTimestamp: Schema2.UnixTimestampMS, | ||
| duration: Schema2.DurationMS.optional(), | ||
| timeout: Schema2.DurationMS.optional(), | ||
| annotations: z.array(Schema2.Annotation).optional(), | ||
| errors: z.array(Schema2.ReportError).optional(), | ||
| parallelIndex: z.number().optional(), | ||
| steps: z.array(Schema2.TestStep).optional(), | ||
| stdout: z.array(Schema2.STDIOEntry).optional(), | ||
| stderr: z.array(Schema2.STDIOEntry).optional(), | ||
| attachments: z.array(Schema2.Attachment).optional() | ||
| }); | ||
| Schema2.Suite = z.object({ | ||
| type: Schema2.SuiteType, | ||
| title: z.string(), | ||
| location: Schema2.Location.optional(), | ||
| get suites() { | ||
| return z.array(Schema2.Suite).optional(); | ||
| }, | ||
| get tests() { | ||
| return z.array(Schema2.Test).optional(); | ||
| } | ||
| }); | ||
| Schema2.Test = z.object({ | ||
| title: z.string(), | ||
| location: Schema2.Location.optional(), | ||
| tags: z.array(z.string()).optional(), | ||
| attempts: z.array(Schema2.RunAttempt) | ||
| }); | ||
| Schema2.SystemUtilizationSample = z.object({ | ||
| dts: Schema2.DurationMS, | ||
| // Must be between 0 and 100 (inclusive). Can be a rational number. | ||
| cpuUtilization: z.number().min(0).max(100), | ||
| // Must be between 0 and 100 (inclusive). Can be a rational number. | ||
| memoryUtilization: z.number().min(0).max(100) | ||
| }); | ||
| Schema2.SystemUtilization = z.object({ | ||
| totalMemoryBytes: z.number().min(0), | ||
| startTimestamp: Schema2.UnixTimestampMS, | ||
| samples: z.array(Schema2.SystemUtilizationSample) | ||
| }); | ||
| Schema2.UtilizationTelemetry = z.tuple([Schema2.DurationMS, z.number().min(0).max(100)]); | ||
| Schema2.Report = z.object({ | ||
| category: z.string().min(1).max(100), | ||
| commitId: Schema2.CommitId, | ||
| relatedCommitIds: z.array(Schema2.CommitId).optional(), | ||
| configPath: Schema2.GitFilePath.optional(), | ||
| url: z.string().optional(), | ||
| environments: z.array(Schema2.Environment).min(1), | ||
| suites: z.array(Schema2.Suite).optional(), | ||
| tests: z.array(Schema2.Test).optional(), | ||
| unattributedErrors: z.array(Schema2.ReportError).optional(), | ||
| startTimestamp: Schema2.UnixTimestampMS, | ||
| duration: Schema2.DurationMS, | ||
| systemUtilization: z.optional(Schema2.SystemUtilization), | ||
| cpuCount: z.number().min(0).optional(), | ||
| cpuAvg: z.array(Schema2.UtilizationTelemetry).optional(), | ||
| cpuMax: z.array(Schema2.UtilizationTelemetry).optional(), | ||
| ram: z.array(Schema2.UtilizationTelemetry).optional(), | ||
| ramBytes: z.number().min(0).optional() | ||
| }); | ||
| })(Schema || (Schema = {})); | ||
| // src/validateReport.ts | ||
| import { Schema } from "@flakiness/flakiness-report"; | ||
| import z from "zod/v4"; | ||
| import z2 from "zod/v4"; | ||
| function validateReport(report) { | ||
@@ -793,3 +923,3 @@ const validation = Schema.Report.safeParse(report); | ||
| const remaining = allIssues.length - shownIssues.length; | ||
| const base = [z.prettifyError(new z.ZodError(shownIssues))]; | ||
| const base = [z2.prettifyError(new z2.ZodError(shownIssues))]; | ||
| if (remaining > 0) | ||
@@ -994,2 +1124,56 @@ base.push(`... and ${remaining} more issue${remaining === 1 ? "" : "s"} ...`); | ||
| // src/readReport.ts | ||
| import fs5 from "fs/promises"; | ||
| import path from "path"; | ||
| async function readReport(reportFolder) { | ||
| reportFolder = path.resolve(reportFolder); | ||
| const text = await fs5.readFile(path.join(reportFolder, "report.json"), "utf-8"); | ||
| const report = JSON.parse(text); | ||
| const attachmentsFolder = path.join(reportFolder, "attachments"); | ||
| let attachmentFiles = []; | ||
| try { | ||
| attachmentFiles = await listFilesRecursively(attachmentsFolder); | ||
| } catch (error) { | ||
| if (error.code !== "ENOENT") { | ||
| throw error; | ||
| } | ||
| } | ||
| const filenameToPath = new Map(attachmentFiles.map((file) => [path.basename(file), file])); | ||
| const attachmentIdToPath = /* @__PURE__ */ new Map(); | ||
| const missingAttachments = /* @__PURE__ */ new Map(); | ||
| visitTests(report, (test) => { | ||
| for (const attempt of test.attempts) { | ||
| for (const attachment of attempt.attachments ?? []) { | ||
| const attachmentPath = filenameToPath.get(attachment.id); | ||
| if (!attachmentPath) { | ||
| missingAttachments.set(attachment.id, attachment); | ||
| } else { | ||
| attachmentIdToPath.set(attachment.id, { | ||
| contentType: attachment.contentType, | ||
| id: attachment.id, | ||
| path: attachmentPath, | ||
| type: "file" | ||
| }); | ||
| } | ||
| } | ||
| } | ||
| }); | ||
| return { | ||
| report, | ||
| attachments: Array.from(attachmentIdToPath.values()), | ||
| missingAttachments: Array.from(missingAttachments.values()) | ||
| }; | ||
| } | ||
| async function listFilesRecursively(dir, result = []) { | ||
| const entries = await fs5.readdir(dir, { withFileTypes: true }); | ||
| for (const entry of entries) { | ||
| const fullPath = path.join(dir, entry.name); | ||
| if (entry.isDirectory()) | ||
| await listFilesRecursively(fullPath, result); | ||
| else | ||
| result.push(fullPath); | ||
| } | ||
| return result; | ||
| } | ||
| // src/showReport.ts | ||
@@ -1000,6 +1184,6 @@ import chalk from "chalk"; | ||
| // src/flakinessProjectConfig.ts | ||
| import fs5 from "fs"; | ||
| import path from "path"; | ||
| import fs6 from "fs"; | ||
| import path2 from "path"; | ||
| function createConfigPath(dir) { | ||
| return path.join(dir, ".flakiness", "config.json"); | ||
| return path2.join(dir, ".flakiness", "config.json"); | ||
| } | ||
@@ -1013,5 +1197,5 @@ var gConfigPath; | ||
| function computeConfigPath() { | ||
| for (let p = process.cwd(); p !== path.resolve(p, ".."); p = path.resolve(p, "..")) { | ||
| for (let p = process.cwd(); p !== path2.resolve(p, ".."); p = path2.resolve(p, "..")) { | ||
| const configPath = createConfigPath(p); | ||
| if (fs5.existsSync(configPath)) | ||
| if (fs6.existsSync(configPath)) | ||
| return configPath; | ||
@@ -1049,3 +1233,3 @@ } | ||
| const configPath = ensureConfigPath(); | ||
| const data = await fs5.promises.readFile(configPath, "utf-8").catch((e) => void 0); | ||
| const data = await fs6.promises.readFile(configPath, "utf-8").catch((e) => void 0); | ||
| const json = data ? JSON.parse(data) : {}; | ||
@@ -1137,4 +1321,4 @@ return new _FlakinessProjectConfig(configPath, json); | ||
| async save() { | ||
| await fs5.promises.mkdir(path.dirname(this._configPath), { recursive: true }); | ||
| await fs5.promises.writeFile(this._configPath, JSON.stringify(this._config, null, 2)); | ||
| await fs6.promises.mkdir(path2.dirname(this._configPath), { recursive: true }); | ||
| await fs6.promises.writeFile(this._configPath, JSON.stringify(this._config, null, 2)); | ||
| } | ||
@@ -1145,5 +1329,5 @@ }; | ||
| import debug2 from "debug"; | ||
| import * as fs6 from "fs"; | ||
| import * as fs7 from "fs"; | ||
| import * as http from "http"; | ||
| import * as path2 from "path"; | ||
| import * as path3 from "path"; | ||
| var log2 = debug2("fk:static_server"); | ||
@@ -1169,3 +1353,3 @@ var StaticServer = class { | ||
| this._pathPrefix = "/" + pathPrefix.replace(/^\//, "").replace(/\/$/, ""); | ||
| this._absoluteFolderPath = path2.resolve(folderPath); | ||
| this._absoluteFolderPath = path3.resolve(folderPath); | ||
| this._cors = cors; | ||
@@ -1266,4 +1450,4 @@ this._server = http.createServer((req, res) => this._handleRequest(req, res)); | ||
| const relativePath = url.slice(this._pathPrefix.length); | ||
| const safeSuffix = path2.normalize(decodeURIComponent(relativePath)).replace(/^(\.\.[\/\\])+/, ""); | ||
| const filePath = path2.join(this._absoluteFolderPath, safeSuffix); | ||
| const safeSuffix = path3.normalize(decodeURIComponent(relativePath)).replace(/^(\.\.[\/\\])+/, ""); | ||
| const filePath = path3.join(this._absoluteFolderPath, safeSuffix); | ||
| if (!filePath.startsWith(this._absoluteFolderPath)) { | ||
@@ -1273,3 +1457,3 @@ this._errorResponse(req, res, 403, "Forbidden"); | ||
| } | ||
| fs6.stat(filePath, (err, stats) => { | ||
| fs7.stat(filePath, (err, stats) => { | ||
| if (err || !stats.isFile()) { | ||
@@ -1279,7 +1463,7 @@ this._errorResponse(req, res, 404, "File Not Found"); | ||
| } | ||
| const ext = path2.extname(filePath).toLowerCase(); | ||
| const ext = path3.extname(filePath).toLowerCase(); | ||
| const contentType = this._mimeTypes[ext] || "application/octet-stream"; | ||
| res.writeHead(200, { "Content-Type": contentType }); | ||
| log2(`[200] ${req.method} ${req.url} -> ${filePath}`); | ||
| const readStream = fs6.createReadStream(filePath); | ||
| const readStream = fs7.createReadStream(filePath); | ||
| readStream.pipe(res); | ||
@@ -1316,19 +1500,19 @@ readStream.on("error", (err2) => { | ||
| // src/writeReport.ts | ||
| import fs7 from "fs"; | ||
| import path3 from "path"; | ||
| import fs8 from "fs"; | ||
| import path4 from "path"; | ||
| async function writeReport(report, attachments, outputFolder) { | ||
| const reportPath = path3.join(outputFolder, "report.json"); | ||
| const attachmentsFolder = path3.join(outputFolder, "attachments"); | ||
| await fs7.promises.rm(outputFolder, { recursive: true, force: true }); | ||
| await fs7.promises.mkdir(outputFolder, { recursive: true }); | ||
| await fs7.promises.writeFile(reportPath, JSON.stringify(report), "utf-8"); | ||
| const reportPath = path4.join(outputFolder, "report.json"); | ||
| const attachmentsFolder = path4.join(outputFolder, "attachments"); | ||
| await fs8.promises.rm(outputFolder, { recursive: true, force: true }); | ||
| await fs8.promises.mkdir(outputFolder, { recursive: true }); | ||
| await fs8.promises.writeFile(reportPath, JSON.stringify(report), "utf-8"); | ||
| if (attachments.length) | ||
| await fs7.promises.mkdir(attachmentsFolder); | ||
| await fs8.promises.mkdir(attachmentsFolder); | ||
| const movedAttachments = []; | ||
| for (const attachment of attachments) { | ||
| const attachmentPath = path3.join(attachmentsFolder, attachment.id); | ||
| const attachmentPath = path4.join(attachmentsFolder, attachment.id); | ||
| if (attachment.type === "file") | ||
| await fs7.promises.cp(attachment.path, attachmentPath); | ||
| await fs8.promises.cp(attachment.path, attachmentPath); | ||
| else if (attachment.type === "buffer") | ||
| await fs7.promises.writeFile(attachmentPath, attachment.body); | ||
| await fs8.promises.writeFile(attachmentPath, attachment.body); | ||
| movedAttachments.push({ | ||
@@ -1347,7 +1531,6 @@ type: "file", | ||
| FlakinessProjectConfig, | ||
| FlakinessReport2 as FlakinessReport, | ||
| GitWorktree, | ||
| RAMUtilization, | ||
| reportUtils_exports as ReportUtils, | ||
| Schema2 as Schema, | ||
| readReport, | ||
| showReport, | ||
@@ -1354,0 +1537,0 @@ uploadReport, |
+5
-2
| { | ||
| "name": "@flakiness/sdk", | ||
| "version": "0.154.0", | ||
| "version": "0.155.0", | ||
| "private": false, | ||
@@ -32,2 +32,3 @@ "repository": { | ||
| "devDependencies": { | ||
| "@flakiness/flakiness-report": "^0.22.0", | ||
| "@types/debug": "^4.1.12", | ||
@@ -40,4 +41,6 @@ "@types/node": "^25.0.3", | ||
| }, | ||
| "peerDependencies": { | ||
| "@flakiness/flakiness-report": "^0.22.0" | ||
| }, | ||
| "dependencies": { | ||
| "@flakiness/flakiness-report": "^0.21.0", | ||
| "chalk": "^5.6.2", | ||
@@ -44,0 +47,0 @@ "debug": "^4.4.3", |
+1
-0
@@ -98,2 +98,3 @@ # Flakiness Node.js SDK | ||
| ### Working with Reports | ||
| - **`readReport()`** - Read a Flakiness report and its attachments from disk | ||
| - **`showReport()`** - Start a local server and open the report in your browser | ||
@@ -100,0 +101,0 @@ - **`uploadReport()`** - Upload reports and attachments to Flakiness.io |
@@ -1,2 +0,1 @@ | ||
| export { FlakinessReport, Schema } from '@flakiness/flakiness-report'; | ||
| export { CIUtils } from './ciUtils.js'; | ||
@@ -7,2 +6,3 @@ export { CPUUtilization } from './cpuUtilization.js'; | ||
| export * as ReportUtils from './reportUtils.js'; | ||
| export { readReport } from './readReport.js'; | ||
| export { showReport } from './showReport.js'; | ||
@@ -9,0 +9,0 @@ export { uploadReport } from './uploadReport.js'; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAC;AAGtE,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"} | ||
| {"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,KAAK,WAAW,MAAM,kBAAkB,CAAC;AAGhD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,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"} |
Network access
Supply chain riskThis module accesses the network.
Found 2 instances in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 14 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 2 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 2 instances in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 14 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
116063
14.14%49
4.26%2660
15.55%106
0.95%7
16.67%27
3.85%+ Added
- Removed
- Removed