@keepsnappy/agent 0.1.0-alpha.17 → 0.1.0-alpha.19
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 +6 -6
- package/dist/appium-driver.js +30 -20
- package/dist/keepsnappy.js +1538 -459
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -70,7 +70,7 @@ Annotated example: `examples/keepsnappy.yml`. Every setting:
|
|
|
70
70
|
|
|
71
71
|
Unknown settings and wrong types are errors, all listed together.
|
|
72
72
|
|
|
73
|
-
Results and exit codes: results never change the exit code by default (ruling D9, no blocking PR checks): `0` also for "More work". `--fail-on-worse` (needs `--wait`) fails the job (exit `3`) only when the verdict computed on that run set is Worse and blocking. Closing a run set never computes its verdict (decision 0031: the operator computes verdicts on demand), so with no computed verdict `--fail-on-worse` checks nothing: the CLI prints `Verdict not computed yet (computed on demand): --fail-on-worse checked nothing` and exits `0`. The CLI exits `2` for a configuration problem (bad or missing `keepsnappy.yml`, unknown or misspelt flags, a glob matching nothing, `--wait` without a branch or key) and `1` for an infrastructure problem (cannot read the device log, an API request failing, an API URL that does not answer as the KeepSnappy API, `--upload` that sent no run: "Blocked"; results stay in the out dir). Failed runs are marked invalid in `runs.ndjson` / `metrics.csv` and ignored by the statistics. The ending summary reads like:
|
|
73
|
+
Results and exit codes: results never change the exit code by default (ruling D9, no blocking PR checks): `0` also for "More work". `--fail-on-worse` (needs `--wait`) fails the job (exit `3`) only when the verdict computed on that run set is Worse and blocking. Closing a run set never computes its verdict (decision 0031: the operator computes verdicts on demand), so with no computed verdict `--fail-on-worse` checks nothing: the CLI prints `Verdict not computed yet (computed on demand): --fail-on-worse checked nothing` and exits `0`. The CLI exits `2` for a configuration problem (bad or missing `keepsnappy.yml`, unknown or misspelt flags, a glob matching nothing, `--wait` without a branch or key) and `1` for an infrastructure problem (cannot read the device log, an API request failing, an API URL that does not answer as the KeepSnappy API, `--upload` that sent no run: "Blocked", or a local run with no valid run; results stay in the out dir). For a local run with no valid run, it prints `No valid run was recorded` with the invalid reasons when known. Failed runs are marked invalid in `runs.ndjson` / `metrics.csv` and ignored by the statistics. The ending summary reads like:
|
|
74
74
|
|
|
75
75
|
```
|
|
76
76
|
7/8 runs valid (dropped: 1 test-failed: exit 1)
|
|
@@ -137,7 +137,7 @@ runner. It writes:
|
|
|
137
137
|
run with data. A measured iteration sends nothing until its end-of-iteration flush, so a run with data completed and
|
|
138
138
|
is never blamed; a Maestro failure stops the session, so later iterations have no data;
|
|
139
139
|
3. finishes every run not yet finished (a run without a single batch is reported as "no data", never judged), closes the
|
|
140
|
-
set (`--wait`: verdicts inline; else on read)
|
|
140
|
+
set (`--wait`: verdicts inline; else on read). It then prints the iterations and the same plain-words verdict as
|
|
141
141
|
`keepsnappy run --upload --wait`, plus `$GITHUB_STEP_SUMMARY` and `<out>/keepsnappy-result.json` (`--out`, default the
|
|
142
142
|
state's directory);
|
|
143
143
|
4. puts the empty stub back into the tokens file, also when a step above failed. The example workflow also deletes the
|
|
@@ -149,10 +149,10 @@ result, `3` with `--fail-on-worse` when the verdict computed on that run set is
|
|
|
149
149
|
verdict it checks nothing and says so, exit `0`), `2` for configuration, `1` when the API fails or nothing could be
|
|
150
150
|
judged ("Blocked": no iteration sent any data).
|
|
151
151
|
|
|
152
|
-
Slack: set `KEEPSNAPPY_SLACK_WEBHOOK` (an incoming-webhook URL kept as a CI secret) and `farm close
|
|
153
|
-
result
|
|
154
|
-
|
|
155
|
-
|
|
152
|
+
Slack: set `KEEPSNAPPY_SLACK_WEBHOOK` (an incoming-webhook URL kept as a CI secret) and `farm close` posts a measurement that sent
|
|
153
|
+
no data ("No result") at once. Results are posted after the verdict is computed, by the operator's recompute job (decision 0031), in
|
|
154
|
+
two lines and one button (docs/mockups/2026-10-26-slack, present `resultSlackPayload`). `$GITHUB_STEP_SUMMARY` gets the same two
|
|
155
|
+
lines: "No result", the computed result, or "Not judged yet · <branch> / Waiting for the judgement" with the run set's page. A Slack failure is printed and never changes the exit code.
|
|
156
156
|
|
|
157
157
|
Declared steps on the farm: `maestro/keepsnappy/step.yaml` / `step.js` / `send-markers.js` (copy them into the suite).
|
|
158
158
|
With a token set, `step.js` only records the marker; `send-markers.js`, run in `end-run.yaml` after each iteration,
|
package/dist/appium-driver.js
CHANGED
|
@@ -507,23 +507,29 @@ class Driver {
|
|
|
507
507
|
});
|
|
508
508
|
await this.cmd("DELETE", "/actions").catch(() => null);
|
|
509
509
|
}
|
|
510
|
-
async drag(from, to, durationMs) {
|
|
510
|
+
async drag(from, to, durationMs, note) {
|
|
511
511
|
to = { x: to.x, y: Math.min(to.y, await this.safeBottomY()) };
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
{
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
512
|
+
const logged = this.log.length;
|
|
513
|
+
try {
|
|
514
|
+
await this.cmd("POST", "/actions", {
|
|
515
|
+
actions: [
|
|
516
|
+
{
|
|
517
|
+
type: "pointer",
|
|
518
|
+
id: "finger1",
|
|
519
|
+
parameters: { pointerType: "touch" },
|
|
520
|
+
actions: [
|
|
521
|
+
{ type: "pointerMove", duration: 0, x: from.x, y: from.y },
|
|
522
|
+
{ type: "pointerDown", button: 0 },
|
|
523
|
+
{ type: "pointerMove", duration: durationMs, x: to.x, y: to.y },
|
|
524
|
+
{ type: "pointerUp", button: 0 }
|
|
525
|
+
]
|
|
526
|
+
}
|
|
527
|
+
]
|
|
528
|
+
});
|
|
529
|
+
} finally {
|
|
530
|
+
if (note && this.log[logged])
|
|
531
|
+
Object.assign(this.log[logged], note);
|
|
532
|
+
}
|
|
527
533
|
await this.cmd("DELETE", "/actions").catch(() => null);
|
|
528
534
|
}
|
|
529
535
|
async relaunch(bundleId = this.bundleId) {
|
|
@@ -726,7 +732,7 @@ import { dirname, join, relative, resolve } from "node:path";
|
|
|
726
732
|
import { fileURLToPath } from "node:url";
|
|
727
733
|
var DRIVER_NAME = "appium";
|
|
728
734
|
function driverVersion() {
|
|
729
|
-
const built = "0.1.0-alpha.
|
|
735
|
+
const built = "0.1.0-alpha.19";
|
|
730
736
|
if (built)
|
|
731
737
|
return built;
|
|
732
738
|
let dir = dirname(fileURLToPath(import.meta.url));
|
|
@@ -800,7 +806,7 @@ async function sendMarkers(fetchImpl, api, markers, opts = {}) {
|
|
|
800
806
|
const url = `${base}/v1/markers`;
|
|
801
807
|
const version = (opts.driverVersion ?? driverVersion)();
|
|
802
808
|
const reported = opts.reported ?? new Set;
|
|
803
|
-
const driverField = { driver: { name: DRIVER_NAME, ...version ? { version } : {}, ...opts.deviceUnit ? { unit: opts.deviceUnit.slice(0, 200) } : {} } };
|
|
809
|
+
const driverField = { driver: { name: DRIVER_NAME, ...version ? { version } : {}, ...opts.deviceUnit ? { unit: opts.deviceUnit.slice(0, 200) } : {}, ...opts.capture ? { capture: opts.capture } : {} } };
|
|
804
810
|
let sent = 0;
|
|
805
811
|
for (const [token, list] of byToken) {
|
|
806
812
|
const trips = [];
|
|
@@ -902,9 +908,11 @@ class Session {
|
|
|
902
908
|
readyWaits = [];
|
|
903
909
|
actionGc;
|
|
904
910
|
endGc;
|
|
911
|
+
capture;
|
|
905
912
|
gcN = 0;
|
|
906
913
|
stepDepth = 0;
|
|
907
914
|
stepLog = [];
|
|
915
|
+
defects = { gestureRetry: 0, items: [] };
|
|
908
916
|
onStepChange = null;
|
|
909
917
|
refinds = 0;
|
|
910
918
|
get staleRefinds() {
|
|
@@ -917,6 +925,7 @@ class Session {
|
|
|
917
925
|
this.api = o.api ?? "";
|
|
918
926
|
this.actionGc = o.actionGc ? "step" : "off";
|
|
919
927
|
this.endGc = o.endGc ?? END_GC_DEFAULT;
|
|
928
|
+
this.capture = o.capture;
|
|
920
929
|
}
|
|
921
930
|
async gc(atEnd = false) {
|
|
922
931
|
if (this.actionGc !== "step" && !(atEnd && this.endGc && this.actionGc === "off"))
|
|
@@ -1293,7 +1302,7 @@ class Session {
|
|
|
1293
1302
|
async endRun() {
|
|
1294
1303
|
if (this.markers.some((m) => m.phase === "start"))
|
|
1295
1304
|
await this.memRead(await this.gc(true));
|
|
1296
|
-
await sendMarkers(this.fetch, this.api, this.markers, { sleep: (ms) => this.driver.sleep(ms), now: () => this.now(), deviceUnit: this.driver.deviceUnit, tokens: [...this.opened], reported: this.told, note: (line) => this.driver.log.push({ ...this.driver.context, cmd: "driver-report", t: this.now(), ms: 0, status: 1, answer: line }) });
|
|
1305
|
+
await sendMarkers(this.fetch, this.api, this.markers, { sleep: (ms) => this.driver.sleep(ms), now: () => this.now(), deviceUnit: this.driver.deviceUnit, capture: this.capture, tokens: [...this.opened], reported: this.told, note: (line) => this.driver.log.push({ ...this.driver.context, cmd: "driver-report", t: this.now(), ms: 0, status: 1, answer: line }) });
|
|
1297
1306
|
const evidence = { linkAt: this.now(), resentAt: null, ackAt: null, gaveUpAt: null };
|
|
1298
1307
|
this.lastFlush = evidence;
|
|
1299
1308
|
const acks = new Set;
|
|
@@ -1460,7 +1469,7 @@ async function runDriver(argv, module, deps = realRunDeps()) {
|
|
|
1460
1469
|
const { api, tokens } = parseTokensJs(readFileSync2(String(a["tokens-js"]), "utf8"));
|
|
1461
1470
|
const log = [];
|
|
1462
1471
|
const driver = new Driver({ hub: HUB, log, headers: { Authorization: auth }, bundleId: module.app.bundleId, platform, fetch: deps.fetch, now: deps.now, sleep: deps.sleep });
|
|
1463
|
-
const t = new Session({ driver, scheme: module.app.scheme, fetch: deps.fetch, api, actionGc: a["action-gc"] === "on", endGc: a["end-gc"] === "on" });
|
|
1472
|
+
const t = new Session({ driver, scheme: module.app.scheme, fetch: deps.fetch, api, actionGc: a["action-gc"] === "on", endGc: a["end-gc"] === "on", capture: capture ? "on" : "off" });
|
|
1464
1473
|
const sessionName = module.sessionName ?? "keepsnappy (appium)";
|
|
1465
1474
|
const device = String(a.device);
|
|
1466
1475
|
const ctx = { fetch: deps.fetch, tokens, journeys, repeat, args: a };
|
|
@@ -1503,6 +1512,7 @@ async function runDriver(argv, module, deps = realRunDeps()) {
|
|
|
1503
1512
|
flushError,
|
|
1504
1513
|
flushOff,
|
|
1505
1514
|
finalFlush,
|
|
1515
|
+
defects: t.defects,
|
|
1506
1516
|
steps: t.stepLog,
|
|
1507
1517
|
iterations,
|
|
1508
1518
|
commands: log
|