@flakiness/sdk 0.131.0 → 0.132.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/cli/cli.js +67 -68
- package/lib/cli/cmd-link.js +1 -145
- package/lib/cli/cmd-login.js +1 -1
- package/lib/cli/cmd-logout.js +1 -1
- package/lib/cli/cmd-show-report.js +6 -3
- package/lib/cli/cmd-upload.js +21 -19
- package/lib/localGit.js +6 -3
- package/lib/localReportApi.js +6 -3
- package/lib/localReportServer.js +6 -3
- package/lib/playwright-test.js +6 -3
- package/package.json +4 -4
- package/types/tsconfig.tsbuildinfo +1 -1
package/lib/cli/cli.js
CHANGED
|
@@ -742,7 +742,7 @@ import path11 from "path";
|
|
|
742
742
|
// ../package.json
|
|
743
743
|
var package_default = {
|
|
744
744
|
name: "flakiness",
|
|
745
|
-
version: "0.
|
|
745
|
+
version: "0.132.0",
|
|
746
746
|
private: true,
|
|
747
747
|
scripts: {
|
|
748
748
|
minor: "./version.mjs minor",
|
|
@@ -1515,6 +1515,23 @@ async function cmdDownload(session2, project, runId) {
|
|
|
1515
1515
|
console.log(`\u2714\uFE0F Saved as ${rootDir}`);
|
|
1516
1516
|
}
|
|
1517
1517
|
|
|
1518
|
+
// src/cli/cmd-link.ts
|
|
1519
|
+
async function cmdLink(session2, slug) {
|
|
1520
|
+
const [orgSlug, projectSlug] = slug.split("/");
|
|
1521
|
+
const project = await session2.api.project.findProject.GET({
|
|
1522
|
+
orgSlug,
|
|
1523
|
+
projectSlug
|
|
1524
|
+
});
|
|
1525
|
+
if (!project) {
|
|
1526
|
+
console.log(`Failed to find project ${slug}`);
|
|
1527
|
+
process.exit(1);
|
|
1528
|
+
}
|
|
1529
|
+
const config = FlakinessConfig.createEmpty();
|
|
1530
|
+
config.setProjectPublicId(project.projectPublicId);
|
|
1531
|
+
await config.save();
|
|
1532
|
+
console.log(`\u2713 Linked to ${session2.endpoint()}/${project.org.orgSlug}/${project.projectSlug}`);
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1518
1535
|
// ../server/lib/common/knownClientIds.js
|
|
1519
1536
|
var KNOWN_CLIENT_IDS = {
|
|
1520
1537
|
OFFICIAL_WEB: "flakiness-io-official-cli",
|
|
@@ -1532,7 +1549,7 @@ async function cmdLogout() {
|
|
|
1532
1549
|
return;
|
|
1533
1550
|
const currentSession = await session2.api.user.currentSession.GET().catch((e) => void 0);
|
|
1534
1551
|
if (currentSession)
|
|
1535
|
-
await session2.api.user.logoutSession.POST({ sessionId: currentSession.sessionPublicId });
|
|
1552
|
+
await session2.api.user.logoutSession.POST({ sessionId: currentSession.sessionPublicId }).catch((e) => void 0);
|
|
1536
1553
|
await FlakinessSession.remove();
|
|
1537
1554
|
}
|
|
1538
1555
|
|
|
@@ -1578,40 +1595,6 @@ async function cmdLogin(endpoint = DEFAULT_FLAKINESS_ENDPOINT) {
|
|
|
1578
1595
|
return session2;
|
|
1579
1596
|
}
|
|
1580
1597
|
|
|
1581
|
-
// src/cli/cmd-link.ts
|
|
1582
|
-
async function cmdLink(slugOrUrl) {
|
|
1583
|
-
let slug = slugOrUrl;
|
|
1584
|
-
let endpoint = DEFAULT_FLAKINESS_ENDPOINT;
|
|
1585
|
-
if (slugOrUrl.startsWith("http://") || slugOrUrl.startsWith("https://")) {
|
|
1586
|
-
const url = URL.parse(slugOrUrl);
|
|
1587
|
-
if (!url) {
|
|
1588
|
-
console.error(`Invalid URL: ${slugOrUrl}`);
|
|
1589
|
-
process.exit(1);
|
|
1590
|
-
}
|
|
1591
|
-
slug = url.pathname.substring(1);
|
|
1592
|
-
endpoint = url.origin;
|
|
1593
|
-
} else if (slugOrUrl.startsWith("flakiness.io/")) {
|
|
1594
|
-
endpoint = "https://flakiness.io";
|
|
1595
|
-
slug = slugOrUrl.substring("flakiness.io/".length);
|
|
1596
|
-
}
|
|
1597
|
-
let session2 = await FlakinessSession.load();
|
|
1598
|
-
if (!session2 || session2.endpoint() !== endpoint)
|
|
1599
|
-
session2 = await cmdLogin(endpoint);
|
|
1600
|
-
const [orgSlug, projectSlug] = slug.split("/");
|
|
1601
|
-
const project = await session2.api.project.findProject.GET({
|
|
1602
|
-
orgSlug,
|
|
1603
|
-
projectSlug
|
|
1604
|
-
});
|
|
1605
|
-
if (!project) {
|
|
1606
|
-
console.log(`Failed to find project ${slug}`);
|
|
1607
|
-
process.exit(1);
|
|
1608
|
-
}
|
|
1609
|
-
const config = FlakinessConfig.createEmpty();
|
|
1610
|
-
config.setProjectPublicId(project.projectPublicId);
|
|
1611
|
-
await config.save();
|
|
1612
|
-
console.log(`\u2713 Linked to ${session2.endpoint()}/${project.org.orgSlug}/${project.projectSlug}`);
|
|
1613
|
-
}
|
|
1614
|
-
|
|
1615
1598
|
// src/cli/cmd-show-report.ts
|
|
1616
1599
|
import chalk from "chalk";
|
|
1617
1600
|
import open2 from "open";
|
|
@@ -1648,8 +1631,10 @@ async function listLocalCommits(gitRoot, head, count) {
|
|
|
1648
1631
|
// %at: Author date as a Unix timestamp (seconds since epoch)
|
|
1649
1632
|
"%an",
|
|
1650
1633
|
// %an: Author name
|
|
1651
|
-
"%s"
|
|
1634
|
+
"%s",
|
|
1652
1635
|
// %s: Subject (the first line of the commit message)
|
|
1636
|
+
"%P"
|
|
1637
|
+
// %P: Parent hashes (space-separated)
|
|
1653
1638
|
].join(FIELD_SEPARATOR);
|
|
1654
1639
|
const command = `git log ${head} -n ${count} --pretty=format:"${prettyFormat}" -z`;
|
|
1655
1640
|
try {
|
|
@@ -1658,13 +1643,14 @@ async function listLocalCommits(gitRoot, head, count) {
|
|
|
1658
1643
|
return [];
|
|
1659
1644
|
}
|
|
1660
1645
|
return stdout.trim().split(RECORD_SEPARATOR).filter((record) => record).map((record) => {
|
|
1661
|
-
const [commitId, timestampStr, author, message] = record.split(FIELD_SEPARATOR);
|
|
1646
|
+
const [commitId, timestampStr, author, message, parentsStr] = record.split(FIELD_SEPARATOR);
|
|
1647
|
+
const parents = parentsStr ? parentsStr.split(" ").filter((p) => p) : [];
|
|
1662
1648
|
return {
|
|
1663
1649
|
commitId,
|
|
1664
1650
|
timestamp: parseInt(timestampStr, 10) * 1e3,
|
|
1665
|
-
// Convert timestamp from seconds to milliseconds
|
|
1666
1651
|
author,
|
|
1667
1652
|
message,
|
|
1653
|
+
parents,
|
|
1668
1654
|
walkIndex: 0
|
|
1669
1655
|
};
|
|
1670
1656
|
});
|
|
@@ -2204,29 +2190,31 @@ import path10 from "path";
|
|
|
2204
2190
|
var warn = (txt) => console.warn(chalk2.yellow(`[flakiness.io] WARN: ${txt}`));
|
|
2205
2191
|
var err = (txt) => console.error(chalk2.red(`[flakiness.io] Error: ${txt}`));
|
|
2206
2192
|
var log = (txt) => console.log(`[flakiness.io] ${txt}`);
|
|
2207
|
-
async function cmdUpload(
|
|
2208
|
-
const fullPath = path10.resolve(relativePath);
|
|
2209
|
-
if (!await fs10.access(fullPath, fs10.constants.F_OK).then(() => true).catch(() => false)) {
|
|
2210
|
-
err(`Path ${fullPath} is not accessible!`);
|
|
2211
|
-
process.exit(1);
|
|
2212
|
-
}
|
|
2213
|
-
const text = await fs10.readFile(fullPath, "utf-8");
|
|
2214
|
-
const report = JSON.parse(text);
|
|
2215
|
-
const attachmentsDir = options.attachmentsDir ?? path10.dirname(fullPath);
|
|
2216
|
-
const { attachmentIdToPath, missingAttachments } = await resolveAttachmentPaths(report, attachmentsDir);
|
|
2217
|
-
if (missingAttachments.length) {
|
|
2218
|
-
warn(`Missing ${missingAttachments.length} attachments`);
|
|
2219
|
-
}
|
|
2193
|
+
async function cmdUpload(relativePaths, options) {
|
|
2220
2194
|
const uploader = new ReportUploader({
|
|
2221
2195
|
flakinessAccessToken: options.accessToken,
|
|
2222
2196
|
flakinessEndpoint: options.endpoint
|
|
2223
2197
|
});
|
|
2224
|
-
const
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2198
|
+
for (const relativePath of relativePaths) {
|
|
2199
|
+
const fullPath = path10.resolve(relativePath);
|
|
2200
|
+
if (!await fs10.access(fullPath, fs10.constants.F_OK).then(() => true).catch(() => false)) {
|
|
2201
|
+
err(`Path ${fullPath} is not accessible!`);
|
|
2202
|
+
process.exit(1);
|
|
2203
|
+
}
|
|
2204
|
+
const text = await fs10.readFile(fullPath, "utf-8");
|
|
2205
|
+
const report = JSON.parse(text);
|
|
2206
|
+
const attachmentsDir = options.attachmentsDir ?? path10.dirname(fullPath);
|
|
2207
|
+
const { attachmentIdToPath, missingAttachments } = await resolveAttachmentPaths(report, attachmentsDir);
|
|
2208
|
+
if (missingAttachments.length) {
|
|
2209
|
+
warn(`Missing ${missingAttachments.length} attachments`);
|
|
2210
|
+
}
|
|
2211
|
+
const upload = uploader.createUpload(report, Array.from(attachmentIdToPath.values()));
|
|
2212
|
+
const uploadResult = await upload.upload();
|
|
2213
|
+
if (!uploadResult.success) {
|
|
2214
|
+
err(`Failed to upload to ${options.endpoint}: ${uploadResult.message}`);
|
|
2215
|
+
} else {
|
|
2216
|
+
log(`\u2713 Uploaded ${uploadResult.reportUrl ?? uploadResult.message ?? ""}`);
|
|
2217
|
+
}
|
|
2230
2218
|
}
|
|
2231
2219
|
}
|
|
2232
2220
|
|
|
@@ -2283,11 +2271,8 @@ async function ensureAccessToken(options) {
|
|
|
2283
2271
|
program.command("upload-playwright-json", { hidden: true }).description("Upload Playwright Test JSON report to the flakiness.io service").argument("<relative-path-to-json>", "Path to the Playwright JSON report file").addOption(optAccessToken).addOption(optEndpoint).action(async (relativePath, options) => runCommand(async () => {
|
|
2284
2272
|
await cmdUploadPlaywrightJson(relativePath, await ensureAccessToken(options));
|
|
2285
2273
|
}));
|
|
2286
|
-
|
|
2287
|
-
program.command("login").description("Login to the Flakiness.io service").addOption(optEndpoint).addOption(optLink).action(async (options) => runCommand(async () => {
|
|
2274
|
+
program.command("login").description("Login to the Flakiness.io service").addOption(optEndpoint).action(async (options) => runCommand(async () => {
|
|
2288
2275
|
await cmdLogin(options.endpoint);
|
|
2289
|
-
if (options.link)
|
|
2290
|
-
await cmdLink(options.link);
|
|
2291
2276
|
}));
|
|
2292
2277
|
program.command("logout").description("Logout from current session").action(async () => runCommand(async () => {
|
|
2293
2278
|
await cmdLogout();
|
|
@@ -2296,10 +2281,24 @@ program.command("whoami").description("Show current logged in user information")
|
|
|
2296
2281
|
await cmdWhoami();
|
|
2297
2282
|
}));
|
|
2298
2283
|
program.command("link").description("Link repository to the flakiness project").addOption(optEndpoint).argument("flakiness.io/org/project", "A URL of the Flakiness.io project").action(async (slugOrUrl, options) => runCommand(async () => {
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2284
|
+
let slug = slugOrUrl;
|
|
2285
|
+
let endpoint = options.endpoint;
|
|
2286
|
+
if (slugOrUrl.startsWith("http://") || slugOrUrl.startsWith("https://")) {
|
|
2287
|
+
const url = URL.parse(slugOrUrl);
|
|
2288
|
+
if (!url) {
|
|
2289
|
+
console.error(`Invalid URL: ${slugOrUrl}`);
|
|
2290
|
+
process.exit(1);
|
|
2291
|
+
}
|
|
2292
|
+
slug = url.pathname.substring(1);
|
|
2293
|
+
endpoint = url.origin;
|
|
2294
|
+
} else if (slugOrUrl.startsWith("flakiness.io/")) {
|
|
2295
|
+
endpoint = "https://flakiness.io";
|
|
2296
|
+
slug = slugOrUrl.substring("flakiness.io/".length);
|
|
2297
|
+
}
|
|
2298
|
+
let session2 = await FlakinessSession.load();
|
|
2299
|
+
if (!session2 || session2.endpoint() !== endpoint || await session2.api.user.whoami.GET().catch((e) => void 0) === void 0)
|
|
2300
|
+
session2 = await cmdLogin(endpoint);
|
|
2301
|
+
await cmdLink(session2, slug);
|
|
2303
2302
|
}));
|
|
2304
2303
|
program.command("unlink").description("Unlink repository from the flakiness project").action(async () => runCommand(async () => {
|
|
2305
2304
|
await cmdUnlink();
|
|
@@ -2352,9 +2351,9 @@ program.command("download").description("Download run").addOption(optSince).addO
|
|
|
2352
2351
|
}
|
|
2353
2352
|
await Promise.all(downloaders);
|
|
2354
2353
|
}));
|
|
2355
|
-
program.command("upload").description("Upload Flakiness report to the flakiness.io service").argument("<relative-
|
|
2354
|
+
program.command("upload").description("Upload Flakiness report to the flakiness.io service").argument("<relative-paths...>", "Paths to the Flakiness report files").addOption(optAccessToken).addOption(optEndpoint).addOption(optAttachmentsDir).action(async (relativePaths, options) => {
|
|
2356
2355
|
await runCommand(async () => {
|
|
2357
|
-
await cmdUpload(
|
|
2356
|
+
await cmdUpload(relativePaths, await ensureAccessToken(options));
|
|
2358
2357
|
});
|
|
2359
2358
|
});
|
|
2360
2359
|
program.command("show").description("Show flakiness report").argument("[relative-path]", "Path to the Flakiness report file or folder that contains `report.json`. (default: flakiness-report)").action(async (arg) => runCommand(async () => {
|
package/lib/cli/cmd-link.js
CHANGED
|
@@ -185,152 +185,8 @@ var FlakinessConfig = class _FlakinessConfig {
|
|
|
185
185
|
}
|
|
186
186
|
};
|
|
187
187
|
|
|
188
|
-
// src/flakinessSession.ts
|
|
189
|
-
import fs2 from "fs/promises";
|
|
190
|
-
import os from "os";
|
|
191
|
-
import path3 from "path";
|
|
192
|
-
|
|
193
|
-
// src/serverapi.ts
|
|
194
|
-
import { TypedHTTP } from "@flakiness/shared/common/typedHttp.js";
|
|
195
|
-
function createServerAPI(endpoint, options) {
|
|
196
|
-
endpoint += "/api/";
|
|
197
|
-
const fetcher = options?.auth ? (url, init) => fetch(url, {
|
|
198
|
-
...init,
|
|
199
|
-
headers: {
|
|
200
|
-
...init.headers,
|
|
201
|
-
"Authorization": `Bearer ${options.auth}`
|
|
202
|
-
}
|
|
203
|
-
}) : fetch;
|
|
204
|
-
if (options?.retries)
|
|
205
|
-
return TypedHTTP.createClient(endpoint, (url, init) => retryWithBackoff(() => fetcher(url, init), options.retries));
|
|
206
|
-
return TypedHTTP.createClient(endpoint, fetcher);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// src/flakinessSession.ts
|
|
210
|
-
var CONFIG_DIR = (() => {
|
|
211
|
-
const configDir = process.platform === "darwin" ? path3.join(os.homedir(), "Library", "Application Support", "flakiness") : process.platform === "win32" ? path3.join(os.homedir(), "AppData", "Roaming", "flakiness") : path3.join(os.homedir(), ".config", "flakiness");
|
|
212
|
-
return configDir;
|
|
213
|
-
})();
|
|
214
|
-
var CONFIG_PATH = path3.join(CONFIG_DIR, "config.json");
|
|
215
|
-
var FlakinessSession = class _FlakinessSession {
|
|
216
|
-
constructor(_config) {
|
|
217
|
-
this._config = _config;
|
|
218
|
-
this.api = createServerAPI(this._config.endpoint, { auth: this._config.token });
|
|
219
|
-
}
|
|
220
|
-
static async loadOrDie() {
|
|
221
|
-
const session = await _FlakinessSession.load();
|
|
222
|
-
if (!session)
|
|
223
|
-
throw new Error(`Please login first with 'npx flakiness login'`);
|
|
224
|
-
return session;
|
|
225
|
-
}
|
|
226
|
-
static async load() {
|
|
227
|
-
const data = await fs2.readFile(CONFIG_PATH, "utf-8").catch((e) => void 0);
|
|
228
|
-
if (!data)
|
|
229
|
-
return void 0;
|
|
230
|
-
const json = JSON.parse(data);
|
|
231
|
-
return new _FlakinessSession(json);
|
|
232
|
-
}
|
|
233
|
-
static async remove() {
|
|
234
|
-
await fs2.unlink(CONFIG_PATH).catch((e) => void 0);
|
|
235
|
-
}
|
|
236
|
-
api;
|
|
237
|
-
endpoint() {
|
|
238
|
-
return this._config.endpoint;
|
|
239
|
-
}
|
|
240
|
-
path() {
|
|
241
|
-
return CONFIG_PATH;
|
|
242
|
-
}
|
|
243
|
-
sessionToken() {
|
|
244
|
-
return this._config.token;
|
|
245
|
-
}
|
|
246
|
-
async save() {
|
|
247
|
-
await fs2.mkdir(CONFIG_DIR, { recursive: true });
|
|
248
|
-
await fs2.writeFile(CONFIG_PATH, JSON.stringify(this._config, null, 2));
|
|
249
|
-
}
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
// ../server/lib/common/knownClientIds.js
|
|
253
|
-
var KNOWN_CLIENT_IDS = {
|
|
254
|
-
OFFICIAL_WEB: "flakiness-io-official-cli",
|
|
255
|
-
OFFICIAL_CLI: "flakiness-io-official-website"
|
|
256
|
-
};
|
|
257
|
-
|
|
258
|
-
// src/cli/cmd-login.ts
|
|
259
|
-
import open from "open";
|
|
260
|
-
import os2 from "os";
|
|
261
|
-
|
|
262
|
-
// src/cli/cmd-logout.ts
|
|
263
|
-
async function cmdLogout() {
|
|
264
|
-
const session = await FlakinessSession.load();
|
|
265
|
-
if (!session)
|
|
266
|
-
return;
|
|
267
|
-
const currentSession = await session.api.user.currentSession.GET().catch((e) => void 0);
|
|
268
|
-
if (currentSession)
|
|
269
|
-
await session.api.user.logoutSession.POST({ sessionId: currentSession.sessionPublicId });
|
|
270
|
-
await FlakinessSession.remove();
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
// src/cli/cmd-login.ts
|
|
274
|
-
var DEFAULT_FLAKINESS_ENDPOINT = "https://flakiness.io";
|
|
275
|
-
async function cmdLogin(endpoint = DEFAULT_FLAKINESS_ENDPOINT) {
|
|
276
|
-
await cmdLogout();
|
|
277
|
-
const api = createServerAPI(endpoint);
|
|
278
|
-
const data = await api.deviceauth.createRequest.POST({
|
|
279
|
-
clientId: KNOWN_CLIENT_IDS.OFFICIAL_CLI,
|
|
280
|
-
name: os2.hostname()
|
|
281
|
-
});
|
|
282
|
-
await open(new URL(data.verificationUrl, endpoint).href);
|
|
283
|
-
console.log(`Please navigate to ${new URL(data.verificationUrl, endpoint)}`);
|
|
284
|
-
let token;
|
|
285
|
-
while (Date.now() < data.deadline) {
|
|
286
|
-
await new Promise((x) => setTimeout(x, 2e3));
|
|
287
|
-
const result = await api.deviceauth.getToken.GET({ deviceCode: data.deviceCode }).catch((e) => void 0);
|
|
288
|
-
if (!result) {
|
|
289
|
-
console.error(`Authorization request was rejected.`);
|
|
290
|
-
process.exit(1);
|
|
291
|
-
}
|
|
292
|
-
token = result.token;
|
|
293
|
-
if (token)
|
|
294
|
-
break;
|
|
295
|
-
}
|
|
296
|
-
if (!token) {
|
|
297
|
-
console.log(`Failed to login.`);
|
|
298
|
-
process.exit(1);
|
|
299
|
-
}
|
|
300
|
-
const session = new FlakinessSession({
|
|
301
|
-
endpoint,
|
|
302
|
-
token
|
|
303
|
-
});
|
|
304
|
-
try {
|
|
305
|
-
const user = await session.api.user.whoami.GET();
|
|
306
|
-
await session.save();
|
|
307
|
-
console.log(`\u2713 Logged in as ${user.userName} (${user.userLogin})`);
|
|
308
|
-
} catch (e) {
|
|
309
|
-
const message = e instanceof Error ? e.message : String(e);
|
|
310
|
-
console.error(`x Failed to login:`, message);
|
|
311
|
-
}
|
|
312
|
-
return session;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
188
|
// src/cli/cmd-link.ts
|
|
316
|
-
async function cmdLink(
|
|
317
|
-
let slug = slugOrUrl;
|
|
318
|
-
let endpoint = DEFAULT_FLAKINESS_ENDPOINT;
|
|
319
|
-
if (slugOrUrl.startsWith("http://") || slugOrUrl.startsWith("https://")) {
|
|
320
|
-
const url = URL.parse(slugOrUrl);
|
|
321
|
-
if (!url) {
|
|
322
|
-
console.error(`Invalid URL: ${slugOrUrl}`);
|
|
323
|
-
process.exit(1);
|
|
324
|
-
}
|
|
325
|
-
slug = url.pathname.substring(1);
|
|
326
|
-
endpoint = url.origin;
|
|
327
|
-
} else if (slugOrUrl.startsWith("flakiness.io/")) {
|
|
328
|
-
endpoint = "https://flakiness.io";
|
|
329
|
-
slug = slugOrUrl.substring("flakiness.io/".length);
|
|
330
|
-
}
|
|
331
|
-
let session = await FlakinessSession.load();
|
|
332
|
-
if (!session || session.endpoint() !== endpoint)
|
|
333
|
-
session = await cmdLogin(endpoint);
|
|
189
|
+
async function cmdLink(session, slug) {
|
|
334
190
|
const [orgSlug, projectSlug] = slug.split("/");
|
|
335
191
|
const project = await session.api.project.findProject.GET({
|
|
336
192
|
orgSlug,
|
package/lib/cli/cmd-login.js
CHANGED
|
@@ -171,7 +171,7 @@ async function cmdLogout() {
|
|
|
171
171
|
return;
|
|
172
172
|
const currentSession = await session.api.user.currentSession.GET().catch((e) => void 0);
|
|
173
173
|
if (currentSession)
|
|
174
|
-
await session.api.user.logoutSession.POST({ sessionId: currentSession.sessionPublicId });
|
|
174
|
+
await session.api.user.logoutSession.POST({ sessionId: currentSession.sessionPublicId }).catch((e) => void 0);
|
|
175
175
|
await FlakinessSession.remove();
|
|
176
176
|
}
|
|
177
177
|
|
package/lib/cli/cmd-logout.js
CHANGED
|
@@ -161,7 +161,7 @@ async function cmdLogout() {
|
|
|
161
161
|
return;
|
|
162
162
|
const currentSession = await session.api.user.currentSession.GET().catch((e) => void 0);
|
|
163
163
|
if (currentSession)
|
|
164
|
-
await session.api.user.logoutSession.POST({ sessionId: currentSession.sessionPublicId });
|
|
164
|
+
await session.api.user.logoutSession.POST({ sessionId: currentSession.sessionPublicId }).catch((e) => void 0);
|
|
165
165
|
await FlakinessSession.remove();
|
|
166
166
|
}
|
|
167
167
|
export {
|
|
@@ -320,8 +320,10 @@ async function listLocalCommits(gitRoot, head, count) {
|
|
|
320
320
|
// %at: Author date as a Unix timestamp (seconds since epoch)
|
|
321
321
|
"%an",
|
|
322
322
|
// %an: Author name
|
|
323
|
-
"%s"
|
|
323
|
+
"%s",
|
|
324
324
|
// %s: Subject (the first line of the commit message)
|
|
325
|
+
"%P"
|
|
326
|
+
// %P: Parent hashes (space-separated)
|
|
325
327
|
].join(FIELD_SEPARATOR);
|
|
326
328
|
const command = `git log ${head} -n ${count} --pretty=format:"${prettyFormat}" -z`;
|
|
327
329
|
try {
|
|
@@ -330,13 +332,14 @@ async function listLocalCommits(gitRoot, head, count) {
|
|
|
330
332
|
return [];
|
|
331
333
|
}
|
|
332
334
|
return stdout.trim().split(RECORD_SEPARATOR).filter((record) => record).map((record) => {
|
|
333
|
-
const [commitId, timestampStr, author, message] = record.split(FIELD_SEPARATOR);
|
|
335
|
+
const [commitId, timestampStr, author, message, parentsStr] = record.split(FIELD_SEPARATOR);
|
|
336
|
+
const parents = parentsStr ? parentsStr.split(" ").filter((p) => p) : [];
|
|
334
337
|
return {
|
|
335
338
|
commitId,
|
|
336
339
|
timestamp: parseInt(timestampStr, 10) * 1e3,
|
|
337
|
-
// Convert timestamp from seconds to milliseconds
|
|
338
340
|
author,
|
|
339
341
|
message,
|
|
342
|
+
parents,
|
|
340
343
|
walkIndex: 0
|
|
341
344
|
};
|
|
342
345
|
});
|
package/lib/cli/cmd-upload.js
CHANGED
|
@@ -288,29 +288,31 @@ var ReportUpload = class {
|
|
|
288
288
|
var warn = (txt) => console.warn(chalk.yellow(`[flakiness.io] WARN: ${txt}`));
|
|
289
289
|
var err = (txt) => console.error(chalk.red(`[flakiness.io] Error: ${txt}`));
|
|
290
290
|
var log = (txt) => console.log(`[flakiness.io] ${txt}`);
|
|
291
|
-
async function cmdUpload(
|
|
292
|
-
const fullPath = path2.resolve(relativePath);
|
|
293
|
-
if (!await fs3.access(fullPath, fs3.constants.F_OK).then(() => true).catch(() => false)) {
|
|
294
|
-
err(`Path ${fullPath} is not accessible!`);
|
|
295
|
-
process.exit(1);
|
|
296
|
-
}
|
|
297
|
-
const text = await fs3.readFile(fullPath, "utf-8");
|
|
298
|
-
const report = JSON.parse(text);
|
|
299
|
-
const attachmentsDir = options.attachmentsDir ?? path2.dirname(fullPath);
|
|
300
|
-
const { attachmentIdToPath, missingAttachments } = await resolveAttachmentPaths(report, attachmentsDir);
|
|
301
|
-
if (missingAttachments.length) {
|
|
302
|
-
warn(`Missing ${missingAttachments.length} attachments`);
|
|
303
|
-
}
|
|
291
|
+
async function cmdUpload(relativePaths, options) {
|
|
304
292
|
const uploader = new ReportUploader({
|
|
305
293
|
flakinessAccessToken: options.accessToken,
|
|
306
294
|
flakinessEndpoint: options.endpoint
|
|
307
295
|
});
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
296
|
+
for (const relativePath of relativePaths) {
|
|
297
|
+
const fullPath = path2.resolve(relativePath);
|
|
298
|
+
if (!await fs3.access(fullPath, fs3.constants.F_OK).then(() => true).catch(() => false)) {
|
|
299
|
+
err(`Path ${fullPath} is not accessible!`);
|
|
300
|
+
process.exit(1);
|
|
301
|
+
}
|
|
302
|
+
const text = await fs3.readFile(fullPath, "utf-8");
|
|
303
|
+
const report = JSON.parse(text);
|
|
304
|
+
const attachmentsDir = options.attachmentsDir ?? path2.dirname(fullPath);
|
|
305
|
+
const { attachmentIdToPath, missingAttachments } = await resolveAttachmentPaths(report, attachmentsDir);
|
|
306
|
+
if (missingAttachments.length) {
|
|
307
|
+
warn(`Missing ${missingAttachments.length} attachments`);
|
|
308
|
+
}
|
|
309
|
+
const upload = uploader.createUpload(report, Array.from(attachmentIdToPath.values()));
|
|
310
|
+
const uploadResult = await upload.upload();
|
|
311
|
+
if (!uploadResult.success) {
|
|
312
|
+
err(`Failed to upload to ${options.endpoint}: ${uploadResult.message}`);
|
|
313
|
+
} else {
|
|
314
|
+
log(`\u2713 Uploaded ${uploadResult.reportUrl ?? uploadResult.message ?? ""}`);
|
|
315
|
+
}
|
|
314
316
|
}
|
|
315
317
|
}
|
|
316
318
|
export {
|
package/lib/localGit.js
CHANGED
|
@@ -12,8 +12,10 @@ async function listLocalCommits(gitRoot, head, count) {
|
|
|
12
12
|
// %at: Author date as a Unix timestamp (seconds since epoch)
|
|
13
13
|
"%an",
|
|
14
14
|
// %an: Author name
|
|
15
|
-
"%s"
|
|
15
|
+
"%s",
|
|
16
16
|
// %s: Subject (the first line of the commit message)
|
|
17
|
+
"%P"
|
|
18
|
+
// %P: Parent hashes (space-separated)
|
|
17
19
|
].join(FIELD_SEPARATOR);
|
|
18
20
|
const command = `git log ${head} -n ${count} --pretty=format:"${prettyFormat}" -z`;
|
|
19
21
|
try {
|
|
@@ -22,13 +24,14 @@ async function listLocalCommits(gitRoot, head, count) {
|
|
|
22
24
|
return [];
|
|
23
25
|
}
|
|
24
26
|
return stdout.trim().split(RECORD_SEPARATOR).filter((record) => record).map((record) => {
|
|
25
|
-
const [commitId, timestampStr, author, message] = record.split(FIELD_SEPARATOR);
|
|
27
|
+
const [commitId, timestampStr, author, message, parentsStr] = record.split(FIELD_SEPARATOR);
|
|
28
|
+
const parents = parentsStr ? parentsStr.split(" ").filter((p) => p) : [];
|
|
26
29
|
return {
|
|
27
30
|
commitId,
|
|
28
31
|
timestamp: parseInt(timestampStr, 10) * 1e3,
|
|
29
|
-
// Convert timestamp from seconds to milliseconds
|
|
30
32
|
author,
|
|
31
33
|
message,
|
|
34
|
+
parents,
|
|
32
35
|
walkIndex: 0
|
|
33
36
|
};
|
|
34
37
|
});
|
package/lib/localReportApi.js
CHANGED
|
@@ -18,8 +18,10 @@ async function listLocalCommits(gitRoot, head, count) {
|
|
|
18
18
|
// %at: Author date as a Unix timestamp (seconds since epoch)
|
|
19
19
|
"%an",
|
|
20
20
|
// %an: Author name
|
|
21
|
-
"%s"
|
|
21
|
+
"%s",
|
|
22
22
|
// %s: Subject (the first line of the commit message)
|
|
23
|
+
"%P"
|
|
24
|
+
// %P: Parent hashes (space-separated)
|
|
23
25
|
].join(FIELD_SEPARATOR);
|
|
24
26
|
const command = `git log ${head} -n ${count} --pretty=format:"${prettyFormat}" -z`;
|
|
25
27
|
try {
|
|
@@ -28,13 +30,14 @@ async function listLocalCommits(gitRoot, head, count) {
|
|
|
28
30
|
return [];
|
|
29
31
|
}
|
|
30
32
|
return stdout.trim().split(RECORD_SEPARATOR).filter((record) => record).map((record) => {
|
|
31
|
-
const [commitId, timestampStr, author, message] = record.split(FIELD_SEPARATOR);
|
|
33
|
+
const [commitId, timestampStr, author, message, parentsStr] = record.split(FIELD_SEPARATOR);
|
|
34
|
+
const parents = parentsStr ? parentsStr.split(" ").filter((p) => p) : [];
|
|
32
35
|
return {
|
|
33
36
|
commitId,
|
|
34
37
|
timestamp: parseInt(timestampStr, 10) * 1e3,
|
|
35
|
-
// Convert timestamp from seconds to milliseconds
|
|
36
38
|
author,
|
|
37
39
|
message,
|
|
40
|
+
parents,
|
|
38
41
|
walkIndex: 0
|
|
39
42
|
};
|
|
40
43
|
});
|
package/lib/localReportServer.js
CHANGED
|
@@ -29,8 +29,10 @@ async function listLocalCommits(gitRoot, head, count) {
|
|
|
29
29
|
// %at: Author date as a Unix timestamp (seconds since epoch)
|
|
30
30
|
"%an",
|
|
31
31
|
// %an: Author name
|
|
32
|
-
"%s"
|
|
32
|
+
"%s",
|
|
33
33
|
// %s: Subject (the first line of the commit message)
|
|
34
|
+
"%P"
|
|
35
|
+
// %P: Parent hashes (space-separated)
|
|
34
36
|
].join(FIELD_SEPARATOR);
|
|
35
37
|
const command = `git log ${head} -n ${count} --pretty=format:"${prettyFormat}" -z`;
|
|
36
38
|
try {
|
|
@@ -39,13 +41,14 @@ async function listLocalCommits(gitRoot, head, count) {
|
|
|
39
41
|
return [];
|
|
40
42
|
}
|
|
41
43
|
return stdout.trim().split(RECORD_SEPARATOR).filter((record) => record).map((record) => {
|
|
42
|
-
const [commitId, timestampStr, author, message] = record.split(FIELD_SEPARATOR);
|
|
44
|
+
const [commitId, timestampStr, author, message, parentsStr] = record.split(FIELD_SEPARATOR);
|
|
45
|
+
const parents = parentsStr ? parentsStr.split(" ").filter((p) => p) : [];
|
|
43
46
|
return {
|
|
44
47
|
commitId,
|
|
45
48
|
timestamp: parseInt(timestampStr, 10) * 1e3,
|
|
46
|
-
// Convert timestamp from seconds to milliseconds
|
|
47
49
|
author,
|
|
48
50
|
message,
|
|
51
|
+
parents,
|
|
49
52
|
walkIndex: 0
|
|
50
53
|
};
|
|
51
54
|
});
|
package/lib/playwright-test.js
CHANGED
|
@@ -474,8 +474,10 @@ async function listLocalCommits(gitRoot, head, count) {
|
|
|
474
474
|
// %at: Author date as a Unix timestamp (seconds since epoch)
|
|
475
475
|
"%an",
|
|
476
476
|
// %an: Author name
|
|
477
|
-
"%s"
|
|
477
|
+
"%s",
|
|
478
478
|
// %s: Subject (the first line of the commit message)
|
|
479
|
+
"%P"
|
|
480
|
+
// %P: Parent hashes (space-separated)
|
|
479
481
|
].join(FIELD_SEPARATOR);
|
|
480
482
|
const command = `git log ${head} -n ${count} --pretty=format:"${prettyFormat}" -z`;
|
|
481
483
|
try {
|
|
@@ -484,13 +486,14 @@ async function listLocalCommits(gitRoot, head, count) {
|
|
|
484
486
|
return [];
|
|
485
487
|
}
|
|
486
488
|
return stdout.trim().split(RECORD_SEPARATOR).filter((record) => record).map((record) => {
|
|
487
|
-
const [commitId, timestampStr, author, message] = record.split(FIELD_SEPARATOR);
|
|
489
|
+
const [commitId, timestampStr, author, message, parentsStr] = record.split(FIELD_SEPARATOR);
|
|
490
|
+
const parents = parentsStr ? parentsStr.split(" ").filter((p) => p) : [];
|
|
488
491
|
return {
|
|
489
492
|
commitId,
|
|
490
493
|
timestamp: parseInt(timestampStr, 10) * 1e3,
|
|
491
|
-
// Convert timestamp from seconds to milliseconds
|
|
492
494
|
author,
|
|
493
495
|
message,
|
|
496
|
+
parents,
|
|
494
497
|
walkIndex: 0
|
|
495
498
|
};
|
|
496
499
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flakiness/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.132.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"bin": {
|
|
6
6
|
"flakiness": "./lib/cli/cli.js"
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"author": "Degu Labs, Inc",
|
|
51
51
|
"license": "Fair Source 100",
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@flakiness/server": "0.
|
|
53
|
+
"@flakiness/server": "0.132.0",
|
|
54
54
|
"@playwright/test": "^1.54.0",
|
|
55
55
|
"@types/babel__code-frame": "^7.0.6",
|
|
56
56
|
"@types/compression": "^1.8.1",
|
|
@@ -58,8 +58,8 @@
|
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
60
|
"@babel/code-frame": "^7.26.2",
|
|
61
|
-
"@flakiness/report": "0.
|
|
62
|
-
"@flakiness/shared": "0.
|
|
61
|
+
"@flakiness/report": "0.132.0",
|
|
62
|
+
"@flakiness/shared": "0.132.0",
|
|
63
63
|
"@rgrove/parse-xml": "^4.2.0",
|
|
64
64
|
"body-parser": "^1.20.3",
|
|
65
65
|
"chalk": "^5.6.2",
|