@keepsnappy/agent 0.1.0-alpha.11 → 0.1.0-alpha.13
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 +50 -50
- package/dist/appium-driver.js +136 -10
- package/dist/keepsnappy.js +87 -90
- package/examples/farm/flows/{perflab → keepsnappy}/begin-run.yaml +1 -1
- package/examples/farm/flows/{perflab → keepsnappy}/end-run.yaml +4 -4
- package/examples/farm/flows/keepsnappy/next-token.js +7 -0
- package/examples/farm/flows/{perflab/run-perflab.yaml → keepsnappy/run-keepsnappy.yaml} +1 -1
- package/examples/farm/flows/{perflab → keepsnappy}/send-markers.js +4 -5
- package/examples/farm/flows/keepsnappy/step-markers.yaml +13 -0
- package/examples/farm/flows/keepsnappy/tokens.js +2 -0
- package/examples/farm/workflows/{perflab-measure.yml → keepsnappy-measure.yml} +20 -20
- package/examples/farm/workflows/perf-device-run.fragment.yml +5 -5
- package/examples/github-actions.yml +18 -18
- package/examples/keepsnappy.yml +3 -3
- package/examples/maestro-steps/e2e-community-and-live-chat.yaml +10 -10
- package/maestro/{perflab → keepsnappy}/send-markers.js +4 -5
- package/maestro/{perflab → keepsnappy}/step.js +10 -11
- package/maestro/keepsnappy/step.yaml +11 -0
- package/package.json +2 -3
- package/examples/farm/flows/perflab/next-token.js +0 -7
- package/examples/farm/flows/perflab/step-markers.yaml +0 -13
- package/examples/farm/flows/perflab/tokens.js +0 -2
- package/examples/perflab.yml +0 -36
- package/maestro/perflab/step.yaml +0 -11
package/dist/keepsnappy.js
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
// apps/agent/src/compat.ts
|
|
4
4
|
import { resolve } from "node:path";
|
|
5
5
|
function envValue(env, name) {
|
|
6
|
-
return env[`KEEPSNAPPY_${name}`]
|
|
6
|
+
return env[`KEEPSNAPPY_${name}`];
|
|
7
7
|
}
|
|
8
8
|
function projectKey(env, name = "KEEPSNAPPY_KEY") {
|
|
9
9
|
return name === "KEEPSNAPPY_KEY" ? envValue(env, "KEY") : env[name];
|
|
10
10
|
}
|
|
11
|
-
var CONFIG_NAMES = ["keepsnappy.yml", "keepsnappy.yaml"
|
|
11
|
+
var CONFIG_NAMES = ["keepsnappy.yml", "keepsnappy.yaml"];
|
|
12
12
|
async function readProjectConfig(read, explicit) {
|
|
13
13
|
if (explicit !== undefined)
|
|
14
14
|
return read(resolve(explicit));
|
|
@@ -413,7 +413,7 @@ function validateConfig(raw, opts = {}) {
|
|
|
413
413
|
}
|
|
414
414
|
const pin = strList("steps.pin", steps.pin);
|
|
415
415
|
const output = section("output", ["dir"], false);
|
|
416
|
-
const outDir = str("output.dir", output.dir, false, "
|
|
416
|
+
const outDir = str("output.dir", output.dir, false, "keepsnappy-out");
|
|
417
417
|
let timeoutSeconds;
|
|
418
418
|
if (raw.timeout_seconds !== undefined) {
|
|
419
419
|
if (typeof raw.timeout_seconds !== "number" || raw.timeout_seconds <= 0)
|
|
@@ -519,12 +519,12 @@ import { join as join11, resolve as resolve3 } from "node:path";
|
|
|
519
519
|
|
|
520
520
|
// apps/agent/src/data-source.ts
|
|
521
521
|
import { join as join2 } from "node:path";
|
|
522
|
-
var
|
|
522
|
+
var KEEPSNAPPY_LOG = "Documents/keepsnappy/log.txt";
|
|
523
523
|
var SAFE_FILE = /^[\w.+:-]+$/;
|
|
524
524
|
var profilePath = (fileName) => {
|
|
525
525
|
if (!SAFE_FILE.test(fileName) || fileName.includes(".."))
|
|
526
526
|
throw new Error(`unsafe profile file name: ${fileName}`);
|
|
527
|
-
return `Documents/
|
|
527
|
+
return `Documents/keepsnappy/${fileName}`;
|
|
528
528
|
};
|
|
529
529
|
function parseSimctlDevices(json, udid) {
|
|
530
530
|
let data;
|
|
@@ -561,7 +561,7 @@ class IosSimulatorDataSource {
|
|
|
561
561
|
return this.deps.fs.readFile(join2(await this.dataDir(bundleId), profilePath(fileName)));
|
|
562
562
|
}
|
|
563
563
|
async fetchLog(bundleId) {
|
|
564
|
-
return this.deps.fs.readFile(join2(await this.dataDir(bundleId),
|
|
564
|
+
return this.deps.fs.readFile(join2(await this.dataDir(bundleId), KEEPSNAPPY_LOG));
|
|
565
565
|
}
|
|
566
566
|
async describeDevice() {
|
|
567
567
|
const r = await this.deps.spawner.run("xcrun", ["simctl", "list", "devices", this.udid === "booted" ? "booted" : "", "-j"].filter(Boolean));
|
|
@@ -580,7 +580,7 @@ class IosDeviceDataSource {
|
|
|
580
580
|
}
|
|
581
581
|
async fetchLog(bundleId) {
|
|
582
582
|
await this.deps.fs.mkdir(this.scratchDir);
|
|
583
|
-
const dest = join2(this.scratchDir, "
|
|
583
|
+
const dest = join2(this.scratchDir, "keepsnappy.log");
|
|
584
584
|
const r = await this.deps.spawner.run("xcrun", [
|
|
585
585
|
"devicectl",
|
|
586
586
|
"device",
|
|
@@ -593,7 +593,7 @@ class IosDeviceDataSource {
|
|
|
593
593
|
"--domain-identifier",
|
|
594
594
|
bundleId,
|
|
595
595
|
"--source",
|
|
596
|
-
|
|
596
|
+
KEEPSNAPPY_LOG,
|
|
597
597
|
"--destination",
|
|
598
598
|
dest
|
|
599
599
|
]);
|
|
@@ -614,7 +614,7 @@ class IosDeviceDataSource {
|
|
|
614
614
|
"--domain-identifier",
|
|
615
615
|
bundleId,
|
|
616
616
|
"--source",
|
|
617
|
-
|
|
617
|
+
KEEPSNAPPY_LOG,
|
|
618
618
|
"--destination",
|
|
619
619
|
dest
|
|
620
620
|
]);
|
|
@@ -651,7 +651,7 @@ class IosDeviceDataSource {
|
|
|
651
651
|
// apps/agent/src/flows.ts
|
|
652
652
|
import { basename, dirname, join as join3 } from "node:path";
|
|
653
653
|
var FLOW_FILE = /\.ya?ml$/i;
|
|
654
|
-
var NOT_FLOWS = new Set(["config.yaml", "config.yml", "keepsnappy.yml", "keepsnappy.yaml", "
|
|
654
|
+
var NOT_FLOWS = new Set(["config.yaml", "config.yml", "keepsnappy.yml", "keepsnappy.yaml", "keepsnappy.yml", "keepsnappy.yaml"]);
|
|
655
655
|
var flowStem = (path) => basename(path).replace(FLOW_FILE, "");
|
|
656
656
|
function flowTags(text) {
|
|
657
657
|
const head = text.split(/^---\s*$/m)[0] ?? "";
|
|
@@ -1193,20 +1193,20 @@ var MEASURES = {
|
|
|
1193
1193
|
worse: "none",
|
|
1194
1194
|
at: ["screen", "launch", "press", "drag", "other"],
|
|
1195
1195
|
producer: "derive",
|
|
1196
|
-
label: "Time of the
|
|
1197
|
-
short: "time of the
|
|
1196
|
+
label: "Time of the KeepSnappy SDK in the window",
|
|
1197
|
+
short: "time of the KeepSnappy SDK",
|
|
1198
1198
|
decimals: 1,
|
|
1199
|
-
what: "Time the
|
|
1199
|
+
what: "Time the KeepSnappy SDK spent on the JavaScript thread after each screen update in the window (reading the update, its profile and, when on, the React export); evidence only, never decides a result. Clock time, so it also holds pauses for garbage collection or other threads while the SDK ran. Not known when the window had more updates than the SDK keeps times for"
|
|
1200
1200
|
},
|
|
1201
1201
|
sdk_hook_commits: {
|
|
1202
1202
|
unit: "count",
|
|
1203
1203
|
worse: "none",
|
|
1204
1204
|
at: ["screen", "launch", "press", "drag", "other"],
|
|
1205
1205
|
producer: "derive",
|
|
1206
|
-
label: "Screen updates the
|
|
1206
|
+
label: "Screen updates the KeepSnappy SDK read",
|
|
1207
1207
|
short: "screen updates the SDK read",
|
|
1208
1208
|
decimals: 0,
|
|
1209
|
-
what: "How many screen updates the
|
|
1209
|
+
what: "How many screen updates the KeepSnappy SDK read in the window, the ones its time is summed over"
|
|
1210
1210
|
},
|
|
1211
1211
|
sdk_hook_capped: {
|
|
1212
1212
|
unit: "count",
|
|
@@ -1216,17 +1216,17 @@ var MEASURES = {
|
|
|
1216
1216
|
label: "Windows with too many updates to time the SDK",
|
|
1217
1217
|
short: "windows the SDK time is not known for",
|
|
1218
1218
|
decimals: 0,
|
|
1219
|
-
what: "Windows of this place with more screen updates than the
|
|
1219
|
+
what: "Windows of this place with more screen updates than the KeepSnappy SDK keeps times for (5000), so its time there is not given"
|
|
1220
1220
|
},
|
|
1221
1221
|
js_thread_app_ms: {
|
|
1222
1222
|
unit: "ms",
|
|
1223
1223
|
worse: "none",
|
|
1224
1224
|
at: ["screen", "launch", "press", "drag", "other"],
|
|
1225
1225
|
producer: "derive",
|
|
1226
|
-
label: "JavaScript thread CPU time without the
|
|
1226
|
+
label: "JavaScript thread CPU time without the KeepSnappy SDK",
|
|
1227
1227
|
short: "JavaScript thread time without the SDK",
|
|
1228
1228
|
decimals: 0,
|
|
1229
|
-
what: "JavaScript thread CPU time in the window minus the time the
|
|
1229
|
+
what: "JavaScript thread CPU time in the window minus the time the KeepSnappy SDK spent after screen updates (not below 0); evidence only, never decides a result. Approximate either way: the thread time is CPU time in 10 ms steps on Android, the SDK time is clock time and includes pauses inside it"
|
|
1230
1230
|
},
|
|
1231
1231
|
main_thread_ms: {
|
|
1232
1232
|
unit: "ms",
|
|
@@ -4205,7 +4205,7 @@ function netMetrics(windows) {
|
|
|
4205
4205
|
// packages/derive/dist/src/sampler.js
|
|
4206
4206
|
var obj6 = (v) => typeof v === "object" && v !== null ? v : {};
|
|
4207
4207
|
var num6 = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined;
|
|
4208
|
-
var SAMPLE_MARK = "
|
|
4208
|
+
var SAMPLE_MARK = "KEEPSNAPPY sample {";
|
|
4209
4209
|
function parseSamples(logText) {
|
|
4210
4210
|
const out = [];
|
|
4211
4211
|
for (const line of logText.split(`
|
|
@@ -4215,7 +4215,7 @@ function parseSamples(logText) {
|
|
|
4215
4215
|
continue;
|
|
4216
4216
|
let raw;
|
|
4217
4217
|
try {
|
|
4218
|
-
raw = JSON.parse(line.slice(sp + 1 + "
|
|
4218
|
+
raw = JSON.parse(line.slice(sp + 1 + "KEEPSNAPPY sample ".length));
|
|
4219
4219
|
} catch {
|
|
4220
4220
|
continue;
|
|
4221
4221
|
}
|
|
@@ -5184,7 +5184,7 @@ function parseMarkersNdjson(text) {
|
|
|
5184
5184
|
return out;
|
|
5185
5185
|
}
|
|
5186
5186
|
// packages/derive/dist/src/window-log.js
|
|
5187
|
-
var WINDOW_MARK = "
|
|
5187
|
+
var WINDOW_MARK = "KEEPSNAPPY window {";
|
|
5188
5188
|
function parseWindows(logText) {
|
|
5189
5189
|
const out = [];
|
|
5190
5190
|
for (const line of logText.split(`
|
|
@@ -5197,7 +5197,7 @@ function parseWindows(logText) {
|
|
|
5197
5197
|
continue;
|
|
5198
5198
|
let raw;
|
|
5199
5199
|
try {
|
|
5200
|
-
raw = JSON.parse(line.slice(sp + 1 + "
|
|
5200
|
+
raw = JSON.parse(line.slice(sp + 1 + "KEEPSNAPPY window ".length));
|
|
5201
5201
|
} catch {
|
|
5202
5202
|
continue;
|
|
5203
5203
|
}
|
|
@@ -5248,10 +5248,7 @@ function startMarkerServer(now = Date.now) {
|
|
|
5248
5248
|
var markerEnv = (url, runId) => ({
|
|
5249
5249
|
KEEPSNAPPY_MARKER_URL: url,
|
|
5250
5250
|
MAESTRO_KEEPSNAPPY_MARKER_URL: url,
|
|
5251
|
-
MAESTRO_KEEPSNAPPY_RUN_ID: runId
|
|
5252
|
-
PERFLAB_MARKER_URL: url,
|
|
5253
|
-
MAESTRO_PERFLAB_MARKER_URL: url,
|
|
5254
|
-
MAESTRO_PERFLAB_RUN_ID: runId
|
|
5251
|
+
MAESTRO_KEEPSNAPPY_RUN_ID: runId
|
|
5255
5252
|
});
|
|
5256
5253
|
|
|
5257
5254
|
// apps/agent/src/upload.ts
|
|
@@ -5297,21 +5294,21 @@ async function uploadRuns(deps, outDir, runs, opts) {
|
|
|
5297
5294
|
skipped.push({ run_id: r.run_id, why: r.invalid_reason || "invalid" });
|
|
5298
5295
|
continue;
|
|
5299
5296
|
}
|
|
5300
|
-
const log = await deps.fs.readFile(join4(outDir, r.run_id, "
|
|
5297
|
+
const log = await deps.fs.readFile(join4(outDir, r.run_id, "keepsnappy.log"));
|
|
5301
5298
|
const windows = windowsInRun(parseWindows(log), r.t0, r.t1);
|
|
5302
5299
|
if (windows.length === 0) {
|
|
5303
5300
|
skipped.push({ run_id: r.run_id, why: "no-windows" });
|
|
5304
5301
|
continue;
|
|
5305
5302
|
}
|
|
5306
5303
|
const externalId = `${opts.externalPrefix}-${r.run_id}`;
|
|
5307
|
-
const created = await call(f, opts.ingestUrl, "/v1/runs", { "x-
|
|
5304
|
+
const created = await call(f, opts.ingestUrl, "/v1/runs", { "x-keepsnappy-key": opts.key }, {
|
|
5308
5305
|
external_id: externalId,
|
|
5309
5306
|
started_at: r.t0,
|
|
5310
5307
|
ended_at: r.t1,
|
|
5311
5308
|
device: { ...opts.device?.model ? { model: opts.device.model } : {}, ...opts.device?.os ? { os: opts.device.os } : {}, ...opts.device?.id ? { id: opts.device.id } : {}, exclusive: true },
|
|
5312
5309
|
meta: {
|
|
5313
5310
|
arm: r.arm,
|
|
5314
|
-
driver: opts.driver ?? "
|
|
5311
|
+
driver: opts.driver ?? "keepsnappy-run",
|
|
5315
5312
|
...opts.meta,
|
|
5316
5313
|
...r.scenario ? { scenario: r.scenario } : {},
|
|
5317
5314
|
...opts.runSetId ? { run_set_id: opts.runSetId } : {}
|
|
@@ -5321,16 +5318,16 @@ async function uploadRuns(deps, outDir, runs, opts) {
|
|
|
5321
5318
|
const token = String(created.run_token ?? "");
|
|
5322
5319
|
if (!runId || !token)
|
|
5323
5320
|
throw new UploadError("POST /v1/runs: response has no run_id/run_token");
|
|
5324
|
-
const items = windows.map((w) => `${w.endWall}
|
|
5321
|
+
const items = windows.map((w) => `${w.endWall} KEEPSNAPPY window ${JSON.stringify(w.raw)}`);
|
|
5325
5322
|
for (let i = 0;i * size < items.length; i++) {
|
|
5326
|
-
await call(f, opts.ingestUrl, "/v1/windows", { "x-
|
|
5323
|
+
await call(f, opts.ingestUrl, "/v1/windows", { "x-keepsnappy-key": opts.key, "x-keepsnappy-run-token": token }, {
|
|
5327
5324
|
batch_id: `${externalId}-${String(i + 1).padStart(4, "0")}`,
|
|
5328
5325
|
items: items.slice(i * size, (i + 1) * size)
|
|
5329
5326
|
});
|
|
5330
5327
|
}
|
|
5331
|
-
const samples = samplesInRun(parseSamples(log), r.t0, r.t1).map((x) => `${x.wall}
|
|
5328
|
+
const samples = samplesInRun(parseSamples(log), r.t0, r.t1).map((x) => `${x.wall} KEEPSNAPPY sample ${JSON.stringify(x.raw)}`);
|
|
5332
5329
|
for (let i = 0;i * size < samples.length; i++) {
|
|
5333
|
-
await call(f, opts.ingestUrl, "/v1/windows", { "x-
|
|
5330
|
+
await call(f, opts.ingestUrl, "/v1/windows", { "x-keepsnappy-key": opts.key, "x-keepsnappy-run-token": token }, {
|
|
5334
5331
|
batch_id: `${externalId}-s${String(i + 1).padStart(4, "0")}`,
|
|
5335
5332
|
items: samples.slice(i * size, (i + 1) * size)
|
|
5336
5333
|
});
|
|
@@ -5342,7 +5339,7 @@ async function uploadRuns(deps, outDir, runs, opts) {
|
|
|
5342
5339
|
for (const m of markers) {
|
|
5343
5340
|
await call(f, opts.ingestUrl, "/v1/markers", { authorization: `Bearer ${token}` }, { step: m.step, phase: m.phase, t_host: m.t_host });
|
|
5344
5341
|
}
|
|
5345
|
-
await call(f, opts.ingestUrl, `/v1/runs/${runId}/finish`, { "x-
|
|
5342
|
+
await call(f, opts.ingestUrl, `/v1/runs/${runId}/finish`, { "x-keepsnappy-key": opts.key }, {});
|
|
5346
5343
|
uploaded++;
|
|
5347
5344
|
}
|
|
5348
5345
|
return { uploaded, skipped };
|
|
@@ -5573,7 +5570,7 @@ function movedCounts(sc) {
|
|
|
5573
5570
|
}
|
|
5574
5571
|
var addCounts = (xs) => xs.reduce((a, c) => ({ worse: a.worse + c.worse, warnings: a.warnings + c.warnings, better: a.better + c.better, noChange: a.noChange + c.noChange, inconclusive: a.inconclusive + c.inconclusive }), { worse: 0, warnings: 0, better: 0, noChange: 0, inconclusive: 0 });
|
|
5575
5572
|
var setupLine = (h) => h?.measured_differently?.length ? `Measured differently (${h.measured_differently.join(", ")}) — ${NOT_BLOCKING}` : null;
|
|
5576
|
-
var keyHeader = (t) => ({ "x-
|
|
5573
|
+
var keyHeader = (t) => ({ "x-keepsnappy-key": t.key });
|
|
5577
5574
|
async function createRunSet(t, body) {
|
|
5578
5575
|
const r = await call(t.fetch ?? fetch, t.url, "/v1/run-sets", keyHeader(t), body);
|
|
5579
5576
|
return { run_set_id: String(r.run_set_id), dashboard_url: String(r.dashboard_url) };
|
|
@@ -7631,7 +7628,7 @@ function summarizeCpuProfile(raw, sessionId, name) {
|
|
|
7631
7628
|
};
|
|
7632
7629
|
}
|
|
7633
7630
|
|
|
7634
|
-
// packages/profile-analysis/dist/src/
|
|
7631
|
+
// packages/profile-analysis/dist/src/keepsnappy/hermes.js
|
|
7635
7632
|
var HERMES_ROOT = "[root]";
|
|
7636
7633
|
function hermesIdleAsCdp(profile) {
|
|
7637
7634
|
const hasParent = new Set;
|
|
@@ -8208,7 +8205,7 @@ function selectTaskCards(profile, durationMs, taskSet, classes) {
|
|
|
8208
8205
|
};
|
|
8209
8206
|
}
|
|
8210
8207
|
|
|
8211
|
-
// packages/profile-analysis/dist/src/
|
|
8208
|
+
// packages/profile-analysis/dist/src/keepsnappy/keys.js
|
|
8212
8209
|
function keyPath(path) {
|
|
8213
8210
|
const normalized = path.replace(/\\/g, "/");
|
|
8214
8211
|
const marker = normalized.lastIndexOf("node_modules/");
|
|
@@ -8231,9 +8228,9 @@ function functionKey(frame, options = {}) {
|
|
|
8231
8228
|
return `${name}@${compactLocation(frame.url, frame.lineNumber, frame.columnNumber)}`;
|
|
8232
8229
|
}
|
|
8233
8230
|
|
|
8234
|
-
// packages/profile-analysis/dist/src/
|
|
8235
|
-
var MEASURING_NAME = "(
|
|
8236
|
-
var SDK_PATH = /(?:^|\/)(?:node_modules\/)?@
|
|
8231
|
+
// packages/profile-analysis/dist/src/keepsnappy/measuring.js
|
|
8232
|
+
var MEASURING_NAME = "(KeepSnappy measuring)";
|
|
8233
|
+
var SDK_PATH = /(?:^|\/)(?:node_modules\/)?@keepsnappy\/react-native\//;
|
|
8237
8234
|
var SDK_FUNCTION_NAMES = new Set([
|
|
8238
8235
|
"recordCommit",
|
|
8239
8236
|
"recordUnmount",
|
|
@@ -8266,8 +8263,8 @@ var SDK_FUNCTION_NAMES = new Set([
|
|
|
8266
8263
|
"finalizeWindow",
|
|
8267
8264
|
"windowAggregate",
|
|
8268
8265
|
"perfLog",
|
|
8269
|
-
"
|
|
8270
|
-
"
|
|
8266
|
+
"handleKeepSnappyDeepLink",
|
|
8267
|
+
"isKeepSnappyUrl",
|
|
8271
8268
|
"logStartup",
|
|
8272
8269
|
"addStartupSection",
|
|
8273
8270
|
"extraStartupSections",
|
|
@@ -8346,7 +8343,7 @@ function foldMeasuring(profile) {
|
|
|
8346
8343
|
return { profile: { ...profile, nodes, samples }, measuringId };
|
|
8347
8344
|
}
|
|
8348
8345
|
|
|
8349
|
-
// packages/profile-analysis/dist/src/
|
|
8346
|
+
// packages/profile-analysis/dist/src/keepsnappy/task-cards.js
|
|
8350
8347
|
var REACT_INTERNALS = new Set([
|
|
8351
8348
|
"propagateParentContextChanges",
|
|
8352
8349
|
"lazilyPropagateParentContextChanges",
|
|
@@ -8484,7 +8481,7 @@ function finishCard(card, measuringMs, profileStartMs) {
|
|
|
8484
8481
|
const cleaned = { ...card, boundaryFrames, culprits: keep(card.culprits) };
|
|
8485
8482
|
const { title, location } = taskCardTitle(cleaned);
|
|
8486
8483
|
const what = card.boundaries === "measured" ? "task" : "stretch of uninterrupted JS work";
|
|
8487
|
-
const measuring = measuringMs >= 1 ? ` (${formatMs(measuringMs)} of it
|
|
8484
|
+
const measuring = measuringMs >= 1 ? ` (${formatMs(measuringMs)} of it KeepSnappy's own measuring)` : "";
|
|
8488
8485
|
return {
|
|
8489
8486
|
...cleaned,
|
|
8490
8487
|
headline: `${title} — a ${formatMs(card.durationMs)} ${what}${measuring}`,
|
|
@@ -8696,7 +8693,7 @@ function originClassTable(frames, origins) {
|
|
|
8696
8693
|
}
|
|
8697
8694
|
// packages/profile-analysis/dist/src/tracesift/lib/card-prompt.js
|
|
8698
8695
|
var DRAWABLE3 = new Set(SHOWN_CLASSES);
|
|
8699
|
-
// packages/profile-analysis/dist/src/
|
|
8696
|
+
// packages/profile-analysis/dist/src/keepsnappy/slice.js
|
|
8700
8697
|
function sliceCpuProfile(profile, window, options = {}) {
|
|
8701
8698
|
const offsetUs = (options.clockOffsetMs ?? 0) * 1000;
|
|
8702
8699
|
const t0Us = window.t0Ms * 1000 - offsetUs;
|
|
@@ -8768,10 +8765,10 @@ function pruneNodes(nodes, samples) {
|
|
|
8768
8765
|
return out;
|
|
8769
8766
|
});
|
|
8770
8767
|
}
|
|
8771
|
-
// packages/profile-analysis/dist/src/
|
|
8768
|
+
// packages/profile-analysis/dist/src/keepsnappy/source-map.js
|
|
8772
8769
|
var BASE64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
8773
8770
|
var BASE64_VALUE = new Map([...BASE64].map((char, index) => [char, index]));
|
|
8774
|
-
// packages/profile-analysis/dist/src/
|
|
8771
|
+
// packages/profile-analysis/dist/src/keepsnappy/symbolicate.js
|
|
8775
8772
|
var FRAMEWORK_PACKAGES = new Set([
|
|
8776
8773
|
"react",
|
|
8777
8774
|
"react-native",
|
|
@@ -8780,9 +8777,9 @@ var FRAMEWORK_PACKAGES = new Set([
|
|
|
8780
8777
|
"scheduler",
|
|
8781
8778
|
"metro-runtime"
|
|
8782
8779
|
]);
|
|
8783
|
-
// packages/profile-analysis/dist/src/
|
|
8780
|
+
// packages/profile-analysis/dist/src/keepsnappy/composition.js
|
|
8784
8781
|
var HOST_PRIMITIVES = new Set(["View", "Text", "Image", "TextInput", "ScrollView"]);
|
|
8785
|
-
// packages/profile-analysis/dist/src/
|
|
8782
|
+
// packages/profile-analysis/dist/src/keepsnappy/summary.js
|
|
8786
8783
|
var DEFAULT_TOP_N = 10;
|
|
8787
8784
|
var NOT_WORK = new Set(["(root)", "[root]", "(idle)", "(program)"]);
|
|
8788
8785
|
var MAX_CALLERS2 = 3;
|
|
@@ -9023,7 +9020,7 @@ async function extract(deps, outDir, ri, memWindow, clockOffsetMs) {
|
|
|
9023
9020
|
let logText = "";
|
|
9024
9021
|
let cpuProfiles = new Map;
|
|
9025
9022
|
try {
|
|
9026
|
-
const log = await deps.fs.readFile(join6(outDir, r.run_id, "
|
|
9023
|
+
const log = await deps.fs.readFile(join6(outDir, r.run_id, "keepsnappy.log"));
|
|
9027
9024
|
logText = log;
|
|
9028
9025
|
cpuProfiles = await readCpuProfiles(deps, join6(outDir, r.run_id), log);
|
|
9029
9026
|
windows = windowsInRun(parseWindows(log), r.t0, r.t1);
|
|
@@ -9124,7 +9121,7 @@ async function measure(deps, source, installer, opts) {
|
|
|
9124
9121
|
let exit = null;
|
|
9125
9122
|
if (!reason) {
|
|
9126
9123
|
const r = await spawner.run(cmd, args, {
|
|
9127
|
-
env: { ...armEnv.get(p.arm), KEEPSNAPPY_RUN_ID: p.runId, KEEPSNAPPY_ARM: p.arm, KEEPSNAPPY_RUN_DIR: dir,
|
|
9124
|
+
env: { ...armEnv.get(p.arm), KEEPSNAPPY_RUN_ID: p.runId, KEEPSNAPPY_ARM: p.arm, KEEPSNAPPY_RUN_DIR: dir, ...opts.markers ? markerEnv(opts.markers.url, p.runId) : {} },
|
|
9128
9125
|
...opts.testTimeoutMs ? { timeoutMs: opts.testTimeoutMs } : {}
|
|
9129
9126
|
});
|
|
9130
9127
|
exit = r.code;
|
|
@@ -9144,7 +9141,7 @@ ${r.stderr}` : ""}`);
|
|
|
9144
9141
|
try {
|
|
9145
9142
|
const text = await source.fetchLog(opts.bundleId);
|
|
9146
9143
|
logText = text;
|
|
9147
|
-
await fs.writeFile(join7(dir, "
|
|
9144
|
+
await fs.writeFile(join7(dir, "keepsnappy.log"), text);
|
|
9148
9145
|
windows = windowsInRun(parseWindows(text), t0, t1);
|
|
9149
9146
|
samples = samplesInRun(parseSamples(text), t0, t1);
|
|
9150
9147
|
cpuProfiles = await pullCpuProfiles(source, opts.bundleId, text, pulled);
|
|
@@ -9153,7 +9150,7 @@ ${r.stderr}` : ""}`);
|
|
|
9153
9150
|
await saveCpuProfiles(deps, dir, cpuProfiles);
|
|
9154
9151
|
} catch (e) {
|
|
9155
9152
|
if (!reason)
|
|
9156
|
-
reason = `no-
|
|
9153
|
+
reason = `no-keepsnappy-log: ${e.message}`;
|
|
9157
9154
|
}
|
|
9158
9155
|
const markers = opts.markers?.forRun(p.runId) ?? [];
|
|
9159
9156
|
if (markers.length)
|
|
@@ -9297,7 +9294,7 @@ async function writeComparisonDataset(deps, baselineDir, outDir) {
|
|
|
9297
9294
|
`);
|
|
9298
9295
|
return dir;
|
|
9299
9296
|
}
|
|
9300
|
-
async function
|
|
9297
|
+
async function keepsnappyRun(deps, source, opts) {
|
|
9301
9298
|
const { runs, rows: raw } = await measure(deps, source, undefined, {
|
|
9302
9299
|
arms: [{ name: "A" }],
|
|
9303
9300
|
repeat: opts.repetitions,
|
|
@@ -9324,7 +9321,7 @@ async function replayRuns(deps, sources, outDir, scenario) {
|
|
|
9324
9321
|
const runs = [];
|
|
9325
9322
|
for (const src of sources) {
|
|
9326
9323
|
const text = await deps.fs.readFile(join9(src.dir, "runs.ndjson")).catch(() => {
|
|
9327
|
-
throw new Error(`--replay ${src.dir}: no runs.ndjson (not a
|
|
9324
|
+
throw new Error(`--replay ${src.dir}: no runs.ndjson (not a keepsnappy out dir)`);
|
|
9328
9325
|
});
|
|
9329
9326
|
for (const line of text.split(`
|
|
9330
9327
|
`)) {
|
|
@@ -9335,7 +9332,7 @@ async function replayRuns(deps, sources, outDir, scenario) {
|
|
|
9335
9332
|
continue;
|
|
9336
9333
|
const id = `${String(runs.length + 1).padStart(3, "0")}-A`;
|
|
9337
9334
|
await deps.fs.mkdir(join9(outDir, id));
|
|
9338
|
-
for (const f of ["
|
|
9335
|
+
for (const f of ["keepsnappy.log", "markers.ndjson", "test.log"]) {
|
|
9339
9336
|
const body = await deps.fs.readFile(join9(src.dir, r.run_id, f)).catch(() => null);
|
|
9340
9337
|
if (body !== null)
|
|
9341
9338
|
await deps.fs.writeFile(join9(outDir, id, f), body);
|
|
@@ -9353,7 +9350,7 @@ async function replayRuns(deps, sources, outDir, scenario) {
|
|
|
9353
9350
|
}
|
|
9354
9351
|
|
|
9355
9352
|
// apps/agent/src/remote-verdict.ts
|
|
9356
|
-
var RUN_INFO = "
|
|
9353
|
+
var RUN_INFO = "keepsnappy-run.json";
|
|
9357
9354
|
async function remoteVerdict(deps, outDir, api, opts = {}) {
|
|
9358
9355
|
let info = {};
|
|
9359
9356
|
try {
|
|
@@ -9404,7 +9401,7 @@ ${output.table}`);
|
|
|
9404
9401
|
}
|
|
9405
9402
|
|
|
9406
9403
|
// apps/agent/src/defaults.ts
|
|
9407
|
-
var DEFAULT_API_URL = "https://keepsnappy-api-
|
|
9404
|
+
var DEFAULT_API_URL = "https://keepsnappy-api-922918702810.europe-west1.run.app";
|
|
9408
9405
|
|
|
9409
9406
|
// apps/agent/src/journeys.ts
|
|
9410
9407
|
import { isAbsolute, relative, resolve as resolve2, sep } from "node:path";
|
|
@@ -9582,7 +9579,7 @@ async function runCommand(deps, o, positionals, rt = { env: process.env, print:
|
|
|
9582
9579
|
}
|
|
9583
9580
|
}
|
|
9584
9581
|
deps.log(`running ${flows.length} flow${flows.length === 1 ? "" : "s"} x${repeat}: ${flows.map((f) => f.name).join(", ")}`);
|
|
9585
|
-
const outcome = await
|
|
9582
|
+
const outcome = await keepsnappyRun(deps, source, {
|
|
9586
9583
|
config,
|
|
9587
9584
|
flows,
|
|
9588
9585
|
outDir: out,
|
|
@@ -9608,7 +9605,7 @@ ${outcome.summary}`);
|
|
|
9608
9605
|
device: { ...device, ...config.device && config.device !== "booted" ? { id: config.device } : {} },
|
|
9609
9606
|
meta: { device_provider: provider, ...git.commit ? { commit_sha: git.commit } : {}, ...git.branch ? { branch: git.branch } : {} },
|
|
9610
9607
|
...runSet ? { runSetId: runSet.run_set_id } : {},
|
|
9611
|
-
driver: config.flows.runner === "maestro" && positionals.length === 0 ? "maestro" : "
|
|
9608
|
+
driver: config.flows.runner === "maestro" && positionals.length === 0 ? "maestro" : "keepsnappy-run",
|
|
9612
9609
|
...api.fetch ? { fetch: api.fetch } : {}
|
|
9613
9610
|
}).catch(infra(`results are saved in ${out}, but the upload failed`));
|
|
9614
9611
|
rt.print(`uploaded ${up.uploaded} runs to ${api.url}${up.skipped.length ? ` (${up.skipped.length} skipped: ${up.skipped.map((x) => `${x.run_id} ${x.why}`).join(", ")})` : ""}`);
|
|
@@ -9646,7 +9643,7 @@ var infra = (what) => (e) => {
|
|
|
9646
9643
|
};
|
|
9647
9644
|
async function writeResult(deps, out, rt, runSet, summary, branch) {
|
|
9648
9645
|
const url = summary?.dashboard_url ?? runSet.dashboard_url;
|
|
9649
|
-
await deps.fs.writeFile(join11(out, "
|
|
9646
|
+
await deps.fs.writeFile(join11(out, "keepsnappy-result.json"), `${JSON.stringify({ run_set_id: runSet.run_set_id, dashboard_url: url, state: summary?.verdicts?.state ?? null, summary }, null, 2)}
|
|
9650
9647
|
`);
|
|
9651
9648
|
const step = rt.env.GITHUB_STEP_SUMMARY;
|
|
9652
9649
|
if (step)
|
|
@@ -9773,7 +9770,7 @@ import { dirname as dirname3, join as join13, resolve as resolve5 } from "node:p
|
|
|
9773
9770
|
// packages/appium-driver/dist/src/links.js
|
|
9774
9771
|
var ALERT_POLL_MS = 250;
|
|
9775
9772
|
var RUN_DEFAULTS = { ttl: 3600, profile: 1, diag: 1 };
|
|
9776
|
-
var route = (scheme) => `${scheme}devtools/
|
|
9773
|
+
var route = (scheme) => `${scheme}devtools/keepsnappy`;
|
|
9777
9774
|
function parseSdkArgs(args) {
|
|
9778
9775
|
return args.split("&").filter(Boolean).map((kv) => {
|
|
9779
9776
|
const i = kv.indexOf("=");
|
|
@@ -9983,7 +9980,7 @@ class Screen {
|
|
|
9983
9980
|
// packages/appium-driver/dist/src/platform.js
|
|
9984
9981
|
var modelOf2 = (device) => device.replace(/-[^-]*$/, "");
|
|
9985
9982
|
var versionOf = (device) => device.replace(/^.*-/, "");
|
|
9986
|
-
var FLUSH_ID = "
|
|
9983
|
+
var FLUSH_ID = "keepsnappy.flushed";
|
|
9987
9984
|
function parseBroadcastAnswer(out, n) {
|
|
9988
9985
|
const data = /data="([^"]*)"/.exec(String(out ?? ""))?.[1];
|
|
9989
9986
|
return data !== undefined && data.startsWith(`gc:${n} `) ? data : null;
|
|
@@ -10045,7 +10042,7 @@ var ANDROID = {
|
|
|
10045
10042
|
uploadFields: {},
|
|
10046
10043
|
async gcCommand(driver, n) {
|
|
10047
10044
|
const out = await driver.execute("mobile: broadcast", {
|
|
10048
|
-
action: `${driver.bundleId}.
|
|
10045
|
+
action: `${driver.bundleId}.keepsnappy.COMMAND`,
|
|
10049
10046
|
package: driver.bundleId,
|
|
10050
10047
|
extras: [["s", "cmd", "gc"], ["i", "n", String(n)]],
|
|
10051
10048
|
flags: "0x10000000"
|
|
@@ -10072,7 +10069,7 @@ import { existsSync, readFileSync, statSync } from "node:fs";
|
|
|
10072
10069
|
import { dirname as dirname2, join as join12, relative as relative2, resolve as resolve4 } from "node:path";
|
|
10073
10070
|
import { fileURLToPath } from "node:url";
|
|
10074
10071
|
function driverVersion() {
|
|
10075
|
-
const built =
|
|
10072
|
+
const built = "0.1.0-alpha.13";
|
|
10076
10073
|
if (built)
|
|
10077
10074
|
return built;
|
|
10078
10075
|
let dir = dirname2(fileURLToPath(import.meta.url));
|
|
@@ -10082,7 +10079,7 @@ function driverVersion() {
|
|
|
10082
10079
|
continue;
|
|
10083
10080
|
try {
|
|
10084
10081
|
const pkg = JSON.parse(readFileSync(file, "utf8"));
|
|
10085
|
-
if (
|
|
10082
|
+
if (pkg.name === "@keepsnappy/appium-driver" && pkg.version)
|
|
10086
10083
|
return pkg.version;
|
|
10087
10084
|
} catch {}
|
|
10088
10085
|
}
|
|
@@ -10331,7 +10328,7 @@ function linksCommand(cmd, argv, rt) {
|
|
|
10331
10328
|
rt.print(activationLink(o.scheme, o.token, set.join("&")));
|
|
10332
10329
|
return 0;
|
|
10333
10330
|
}
|
|
10334
|
-
var maestroLinkFields = (sdkArgs = "") => ({
|
|
10331
|
+
var maestroLinkFields = (sdkArgs = "") => ({ keepsnappyLinkArgs: linkArgs(sdkArgs) });
|
|
10335
10332
|
|
|
10336
10333
|
// apps/agent/src/farm.ts
|
|
10337
10334
|
var STATE_VERSION = 1;
|
|
@@ -10358,17 +10355,17 @@ function instrumentFlags(f) {
|
|
|
10358
10355
|
const journey = f["journey-version"] ?? hash;
|
|
10359
10356
|
return { ...driver ? { "driver-version": driver } : {}, ...journey ? { "journey-version": journey } : {} };
|
|
10360
10357
|
}
|
|
10361
|
-
var TOKENS_STUB = "// Replaced by `keepsnappy farm open` for one upload. Never commit real tokens.\noutput.
|
|
10358
|
+
var TOKENS_STUB = "// Replaced by `keepsnappy farm open` for one upload. Never commit real tokens.\noutput.keepsnappyTokens = {};\n";
|
|
10362
10359
|
var JOURNEY = /^[A-Za-z0-9][A-Za-z0-9._-]{0,199}$/;
|
|
10363
10360
|
var DEFAULT_TTL = 21600;
|
|
10364
10361
|
var POLL_MS = 5000;
|
|
10365
10362
|
function tokensJs(api, runSetId, tokens, links = maestroLinkFields()) {
|
|
10366
10363
|
return [
|
|
10367
10364
|
`// Generated by \`keepsnappy farm open\` for run set ${runSetId}. Overlaid into the suite for one upload; never commit.`,
|
|
10368
|
-
`output.
|
|
10369
|
-
`output.
|
|
10370
|
-
`output.
|
|
10371
|
-
`output.
|
|
10365
|
+
`output.keepsnappyApi = ${JSON.stringify(api.replace(/\/+$/, ""))};`,
|
|
10366
|
+
`output.keepsnappyRunSet = ${JSON.stringify(runSetId)};`,
|
|
10367
|
+
`output.keepsnappyTokens = ${JSON.stringify(tokens)};`,
|
|
10368
|
+
`output.keepsnappyLinkArgs = ${JSON.stringify(links.keepsnappyLinkArgs)};`,
|
|
10372
10369
|
""
|
|
10373
10370
|
].join(`
|
|
10374
10371
|
`);
|
|
@@ -10446,7 +10443,7 @@ async function farmOpen(deps, f, rt) {
|
|
|
10446
10443
|
if (!Number.isInteger(ttl) || ttl < 60)
|
|
10447
10444
|
problems.push("--ttl-seconds must be a whole number >= 60");
|
|
10448
10445
|
if (!f["tokens-js"])
|
|
10449
|
-
problems.push("--tokens-js <path> is required (the file the suite overlay puts at flows/
|
|
10446
|
+
problems.push("--tokens-js <path> is required (the file the suite overlay puts at flows/keepsnappy/tokens.js)");
|
|
10450
10447
|
if (!f.state)
|
|
10451
10448
|
problems.push("--state <path> is required (read by keepsnappy farm close)");
|
|
10452
10449
|
if (problems.length)
|
|
@@ -10715,7 +10712,7 @@ async function closeRunSet(deps, f, rt, state, statePath) {
|
|
|
10715
10712
|
await deps.fs.writeFile(statePath, `${JSON.stringify(state2, null, 2)}
|
|
10716
10713
|
`);
|
|
10717
10714
|
await deps.fs.mkdir(out);
|
|
10718
|
-
await deps.fs.writeFile(join13(out, "
|
|
10715
|
+
await deps.fs.writeFile(join13(out, "keepsnappy-result.json"), `${JSON.stringify({ run_set_id: state.run_set_id, dashboard_url: summary.dashboard_url, state: state2.result.state, session: { status: session.status, message: session.message }, summary }, null, 2)}
|
|
10719
10716
|
`);
|
|
10720
10717
|
await githubOutputs(deps, rt, { state: state2.result.state ?? "none", dashboard_url: summary.dashboard_url, run_set_id: state.run_set_id });
|
|
10721
10718
|
const step = rt.env.GITHUB_STEP_SUMMARY;
|
|
@@ -10896,7 +10893,7 @@ class BrowserStack {
|
|
|
10896
10893
|
}
|
|
10897
10894
|
async runMaestro(b) {
|
|
10898
10895
|
const appUrl = await this.uploadApp(b.app, b.customId);
|
|
10899
|
-
const work = join15(this.o.tmpDir ?? "/tmp", `
|
|
10896
|
+
const work = join15(this.o.tmpDir ?? "/tmp", `keepsnappy-suite-${(this.o.uniqueId ?? randomUUID)()}`);
|
|
10900
10897
|
let suiteUrl;
|
|
10901
10898
|
try {
|
|
10902
10899
|
const zip = await this.zipSuite(b, work);
|
|
@@ -10914,8 +10911,8 @@ class BrowserStack {
|
|
|
10914
10911
|
testSuite: suiteUrl,
|
|
10915
10912
|
devices: [b.device],
|
|
10916
10913
|
setEnvVariables: { ...b.env, RUN_ID: b.runId },
|
|
10917
|
-
buildTag: `
|
|
10918
|
-
customBuildName: `
|
|
10914
|
+
buildTag: `keepsnappy-${b.runId}`,
|
|
10915
|
+
customBuildName: `keepsnappy ${b.runId} ${b.platform}`,
|
|
10919
10916
|
execute: [b.execute],
|
|
10920
10917
|
deviceLogs: true,
|
|
10921
10918
|
...b.localIdentifier ? { local: "true", localIdentifier: b.localIdentifier } : {},
|
|
@@ -11048,7 +11045,7 @@ function nodeFarmRunPorts(deps, rt) {
|
|
|
11048
11045
|
if (!user || !key)
|
|
11049
11046
|
throw new ConfigError(["BROWSERSTACK_USERNAME and BROWSERSTACK_ACCESS_KEY must be set"]);
|
|
11050
11047
|
const tmp = rt.env.RUNNER_TEMP ?? rt.env.TMPDIR ?? "/tmp";
|
|
11051
|
-
const dir = join16(tmp, "
|
|
11048
|
+
const dir = join16(tmp, "keepsnappy-bs-local");
|
|
11052
11049
|
return {
|
|
11053
11050
|
apps: new DefaultAppResolver(deps, rt.env),
|
|
11054
11051
|
provider: new BrowserStack(deps, { credentials: { user, key }, tmpDir: tmp, ...rt.fetch ? { fetch: rt.fetch } : {}, ...rt.sleep ? { sleep: rt.sleep } : {}, ...rt.now ? { now: rt.now } : {} }),
|
|
@@ -11144,7 +11141,7 @@ function substitute(value, s) {
|
|
|
11144
11141
|
return value.replace(/\{tunnel:(\d+)\}/g, (_m, port) => `http://bs-local.com:${port}`).replace(/\{run_id\}/g, s.runId ?? "{run_id}").replace(/\{out\}/g, s.out ?? "{out}").replace(/\{tokens_js\}/g, s.tokensJs ?? "{tokens_js}").replace(/\{run_set_id\}/g, s.runSetId ?? "{run_set_id}");
|
|
11145
11142
|
}
|
|
11146
11143
|
function secretsOf(p, f, env) {
|
|
11147
|
-
const out = [env.KEEPSNAPPY_KEY, env.
|
|
11144
|
+
const out = [env.KEEPSNAPPY_KEY, env.KEEPSNAPPY_SLACK_WEBHOOK, env.BROWSERSTACK_ACCESS_KEY, projectKey(env, f["key-env"]), env.EXPO_TOKEN, envValue(env, "SLACK_WEBHOOK")];
|
|
11148
11145
|
for (const [k, v] of p.env)
|
|
11149
11146
|
if (SECRETISH.test(k))
|
|
11150
11147
|
out.push(v);
|
|
@@ -11161,10 +11158,10 @@ function printPlan(p, f, rt) {
|
|
|
11161
11158
|
line("keepsnappy farm run: dry run, no request is made and nothing is written");
|
|
11162
11159
|
line(` 1. validate: ${p.journeys.join(", ")} x ${p.repeat} on ${p.device} (${p.platform}), driver ${p.driver}`);
|
|
11163
11160
|
line(` 2. resolve the app: ${p.app.startsWith("eas:") ? `eas-cli build:view ${p.app.slice(4)}, download into ${p.out}` : p.app.startsWith("bs://") ? "bs:// passes through" : `${p.app} (local file)`}`);
|
|
11164
|
-
line(` 3. farm open -> ${join16(p.out, "
|
|
11161
|
+
line(` 3. farm open -> ${join16(p.out, "keepsnappy-tokens.js")}, ${join16(p.out, "keepsnappy-farm.json")} (POST /v1/run-sets, then POST /v1/runs x ${p.journeys.length * p.repeat})`);
|
|
11165
11162
|
line(` 4. tunnel: ${p.ports.length ? `BrowserStackLocal for bs-local.com ports ${p.ports.join(", ")}, identifier = run id` : "none (no --tunnel-for)"}`);
|
|
11166
11163
|
if (p.driver === "maestro") {
|
|
11167
|
-
line(` 5. maestro on BrowserStack: upload app, zip ${f["suite-dir"]} with the tokens at ${f["tokens-path"] ?? "flows/
|
|
11164
|
+
line(` 5. maestro on BrowserStack: upload app, zip ${f["suite-dir"]} with the tokens at ${f["tokens-path"] ?? "flows/keepsnappy/tokens.js"}, upload suite, POST build (execute ${f.execute}), poll`);
|
|
11168
11165
|
} else {
|
|
11169
11166
|
line(` 5. appium: ${f["journey-module"] ? `built-in driver, journey module ${f["journey-module"]}` : `node ${f["driver-script"]}`} --platform ${p.platform} --device ... --tokens-js ... --journeys ... --repeat ${p.repeat}${p.driverArgs.length ? ` ${p.driverArgs.map((a) => substitute(a, {})).join(" ")}` : ""}`);
|
|
11170
11167
|
}
|
|
@@ -11183,7 +11180,7 @@ async function runDriver2(deps, rt, f, p, ports, ctx) {
|
|
|
11183
11180
|
app: ctx.app,
|
|
11184
11181
|
...f["custom-id"] ? { customId: f["custom-id"] } : {},
|
|
11185
11182
|
suiteDir: resolve6(f["suite-dir"]),
|
|
11186
|
-
tokensPath: f["tokens-path"] ?? "flows/
|
|
11183
|
+
tokensPath: f["tokens-path"] ?? "flows/keepsnappy/tokens.js",
|
|
11187
11184
|
tokensJs: ctx.tokensJs,
|
|
11188
11185
|
execute: f.execute,
|
|
11189
11186
|
runId: ctx.runId,
|
|
@@ -11254,7 +11251,7 @@ async function runDriver2(deps, rt, f, p, ports, ctx) {
|
|
|
11254
11251
|
}
|
|
11255
11252
|
async function farmRun(deps, f, rt, ports) {
|
|
11256
11253
|
const p = planFarmRun(f);
|
|
11257
|
-
const statePath = join16(p.out, "
|
|
11254
|
+
const statePath = join16(p.out, "keepsnappy-farm.json");
|
|
11258
11255
|
if (await deps.fs.exists(statePath))
|
|
11259
11256
|
throw new ConfigError([`${statePath} exists: a run set was opened here before; use another --out or remove ${p.out} (close it first with keepsnappy farm close)`]);
|
|
11260
11257
|
if (f["dry-run"]) {
|
|
@@ -11262,7 +11259,7 @@ async function farmRun(deps, f, rt, ports) {
|
|
|
11262
11259
|
return EXIT.ok;
|
|
11263
11260
|
}
|
|
11264
11261
|
const farm = ports ?? nodeFarmRunPorts(deps, rt);
|
|
11265
|
-
const tokensJs = join16(p.out, "
|
|
11262
|
+
const tokensJs = join16(p.out, "keepsnappy-tokens.js");
|
|
11266
11263
|
await deps.fs.mkdir(p.out);
|
|
11267
11264
|
const resolved = await farm.apps.resolve(p.app, { outDir: p.out });
|
|
11268
11265
|
const commit = f.commit ?? resolved.commit ?? undefined;
|
|
@@ -11290,7 +11287,7 @@ async function farmRun(deps, f, rt, ports) {
|
|
|
11290
11287
|
return openCode;
|
|
11291
11288
|
opened = true;
|
|
11292
11289
|
const state = JSON.parse(await deps.fs.readFile(statePath));
|
|
11293
|
-
const runId = f["run-id"] ?? `
|
|
11290
|
+
const runId = f["run-id"] ?? `keepsnappy-${p.platform}-${state.run_set_id.slice(0, 8)}`;
|
|
11294
11291
|
const ctx = { runId, out: p.out, tokensJs, runSetId: state.run_set_id, app: resolved.app };
|
|
11295
11292
|
try {
|
|
11296
11293
|
await deps.spawner.run("rm", ["-f", join16(p.out, `browserstack.${p.platform}.json`)]);
|
|
@@ -11374,7 +11371,7 @@ async function put(f, upload, body) {
|
|
|
11374
11371
|
async function uploadSourcemaps(opts) {
|
|
11375
11372
|
const f = opts.fetch ?? fetch;
|
|
11376
11373
|
const read = opts.readFile ?? ((p) => readFile4(p, "utf8"));
|
|
11377
|
-
const headers = { "x-
|
|
11374
|
+
const headers = { "x-keepsnappy-key": opts.key };
|
|
11378
11375
|
const out = [];
|
|
11379
11376
|
for (const file of opts.files) {
|
|
11380
11377
|
let parsed;
|
|
@@ -11628,13 +11625,13 @@ async function get(t, path, query = {}) {
|
|
|
11628
11625
|
for (const [k, v] of Object.entries(query))
|
|
11629
11626
|
if (v !== undefined && v !== "")
|
|
11630
11627
|
u.searchParams.set(k, String(v));
|
|
11631
|
-
const r = await (t.fetch ?? fetch)(u, { headers: { "x-
|
|
11628
|
+
const r = await (t.fetch ?? fetch)(u, { headers: { "x-keepsnappy-key": t.key, accept: "application/json" } });
|
|
11632
11629
|
const text = await r.text();
|
|
11633
11630
|
const body = text ? JSON.parse(text) : {};
|
|
11634
11631
|
if (!r.ok) {
|
|
11635
11632
|
const code = typeof body.error === "string" ? body.error : String(r.status);
|
|
11636
11633
|
const message = typeof body.message === "string" ? body.message : code;
|
|
11637
|
-
const hint = r.status === 401 ? " (check KEEPSNAPPY_KEY
|
|
11634
|
+
const hint = r.status === 401 ? " (check KEEPSNAPPY_KEY)" : r.status === 403 ? " (the key needs the read or run scope)" : "";
|
|
11638
11635
|
throw new ApiError(r.status, code, `${message}${hint}`);
|
|
11639
11636
|
}
|
|
11640
11637
|
return body;
|
|
@@ -11770,7 +11767,7 @@ var USAGE = `keepsnappy <command>
|
|
|
11770
11767
|
farm close --state <file> [--wait [--fail-on-worse]] [--bs-build browserstack.ios.json] [--settle-seconds 60] [--max-wait-seconds 300] [--out DIR]
|
|
11771
11768
|
farm run --app <eas:ID|file.ipa|bs://ID> --journeys a,b [--repeat 5] --device "iPhone 15 Pro-17" [--platform ios|android] [--driver maestro|appium]
|
|
11772
11769
|
[--tunnel-for localhost:PORT ...] [--env KEY=VALUE ...] (values may use {tunnel:PORT} {run_id} {out} {tokens_js} {run_set_id})
|
|
11773
|
-
maestro: --suite-dir DIR --execute FLOW [--tokens-path flows/
|
|
11770
|
+
maestro: --suite-dir DIR --execute FLOW [--tokens-path flows/keepsnappy/tokens.js] [--maestro-version V]
|
|
11774
11771
|
appium: --journey-module FILE | --driver-script FILE [--driver-arg ARG ...]
|
|
11775
11772
|
[--branch NAME --commit SHA] [--wait [--fail-on-worse]] [--out DIR] [--dry-run] (open + tunnel + device + close; docs/plans/54a)
|
|
11776
11773
|
extract <out-dir> --ri-capture observations.ndjson [--mem-window NAME]
|
|
@@ -11902,7 +11899,7 @@ async function main2(argv) {
|
|
|
11902
11899
|
if (platform === "ios-device" && !o.device)
|
|
11903
11900
|
throw new Error("--device <udid> is required for ios-device");
|
|
11904
11901
|
const arms = parseArmEnv(o["arm-env"], parseArms(o.arms));
|
|
11905
|
-
const out = resolve7(o.out ?? `
|
|
11902
|
+
const out = resolve7(o.out ?? `keepsnappy-${new Date().toISOString().replace(/[:.]/g, "-")}`);
|
|
11906
11903
|
const udid = o.device ?? "booted";
|
|
11907
11904
|
const source = platform === "ios-sim" ? new IosSimulatorDataSource(deps, udid) : new IosDeviceDataSource(deps, udid, resolve7(out, ".scratch"));
|
|
11908
11905
|
const installer = platform === "ios-sim" ? new IosSimulatorInstaller(deps, udid) : new IosDeviceInstaller(deps, udid);
|