adb-ready 0.6.0 → 0.8.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/CHANGELOG.md +39 -1
- package/COMPATIBILITY.md +31 -0
- package/README.md +18 -1
- package/dist/cli.js +2730 -80
- package/docs/automation.md +89 -0
- package/docs/completions.md +61 -0
- package/docs/configuration.md +6 -0
- package/docs/firebase-test-lab.md +126 -0
- package/docs/gradle-managed-devices.md +105 -0
- package/docs/target-pools.md +151 -0
- package/docs/targets-and-wireless.md +21 -0
- package/docs/troubleshooting.md +3 -0
- package/examples/README.md +6 -0
- package/examples/ci-emulator/README.md +32 -0
- package/examples/ci-emulator/adb-ready.config.json +20 -0
- package/examples/ci-emulator/dev-service.mjs +14 -0
- package/examples/ci-emulator/verify-emulator.mjs +108 -0
- package/examples/ci-physical/README.md +51 -0
- package/examples/ci-physical/adb-ready.config.json +20 -0
- package/examples/ci-physical/dev-service.mjs +14 -0
- package/examples/ci-physical/github-actions.yml +56 -0
- package/examples/ci-physical/run-job.mjs +77 -0
- package/examples/ci-physical/verify-device.mjs +90 -0
- package/examples/target-pools/README.md +22 -0
- package/examples/target-pools/adb-ready.config.json +29 -0
- package/package.json +2 -2
- package/schema/agent-tools-v1.json +1 -1
- package/schema/config-v1.schema.json +86 -0
- package/skills/adb-ready/SKILL.md +2 -2
package/docs/automation.md
CHANGED
|
@@ -198,6 +198,20 @@ Preview the complete project plan before a device is allocated:
|
|
|
198
198
|
adb-ready run --preset expo --dry-run --json -- npm run test:e2e
|
|
199
199
|
```
|
|
200
200
|
|
|
201
|
+
### Fan out over an explicit pool
|
|
202
|
+
|
|
203
|
+
Named project pools repeat the same bounded verifier without weakening the
|
|
204
|
+
single-target run contract:
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
adb-ready run --pool smoke --max-concurrency 2 -- npm run test:e2e
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Each member keeps its own target lease, session, result envelope, evidence, and
|
|
211
|
+
cleanup. Required failures fail the aggregate; optional failures remain
|
|
212
|
+
visible. Queueing is bounded and host-local, never an inferred distributed
|
|
213
|
+
lock. See [Target pools and fan-out](./target-pools.md).
|
|
214
|
+
|
|
201
215
|
### Start an existing AVD and deploy the intended build
|
|
202
216
|
|
|
203
217
|
For a complete local or CI-owned emulator job, name one existing AVD and either
|
|
@@ -265,3 +279,78 @@ fragile parsing of human log messages.
|
|
|
265
279
|
USB passthrough, emulators, remote ADB servers, and device labs remain the CI
|
|
266
280
|
environment's responsibility. ADB Ready reports the observed boundary instead
|
|
267
281
|
of simulating a connected device.
|
|
282
|
+
|
|
283
|
+
### GitHub-hosted emulator
|
|
284
|
+
|
|
285
|
+
The repository continuously runs a complete finite ADB Ready job on a real
|
|
286
|
+
headless Linux emulator. The runner layer creates and owns the AVD; ADB Ready
|
|
287
|
+
binds to its exact serial, verifies boot and unlock state, executes the bounded
|
|
288
|
+
check, writes normalized NDJSON and evidence, and leaves emulator teardown to
|
|
289
|
+
the owning layer.
|
|
290
|
+
|
|
291
|
+
Use the maintained, commit-pinned workflow and fixture as the starting point:
|
|
292
|
+
|
|
293
|
+
- [Android emulator workflow](../.github/workflows/android-emulator.yml)
|
|
294
|
+
- [CI emulator fixture](../examples/ci-emulator/)
|
|
295
|
+
|
|
296
|
+
The evidence upload uses `if: always()` so a product assertion or verifier
|
|
297
|
+
failure retains the same manifest, result, JUnit, native files, and GitHub step
|
|
298
|
+
summary as a successful run. A failure before ADB Ready starts cannot produce
|
|
299
|
+
an ADB Ready bundle and is reported by the provisioning step instead.
|
|
300
|
+
|
|
301
|
+
### Self-hosted physical target
|
|
302
|
+
|
|
303
|
+
Use the maintained [physical-device recipe](../examples/ci-physical/) when a
|
|
304
|
+
dedicated self-hosted runner owns one pre-authorized Android phone or tablet.
|
|
305
|
+
The workflow is manual-only, routes through an explicit `android-device`
|
|
306
|
+
runner label, queues competing GitHub jobs, and still relies on ADB Ready's
|
|
307
|
+
host-local target lease as the final ownership boundary.
|
|
308
|
+
|
|
309
|
+
The configured serial must match one `adb devices -l` row exactly. Missing,
|
|
310
|
+
`unauthorized`, `offline`, replaced, and concurrently owned targets fail before
|
|
311
|
+
the verifier can mutate another device. ADB Ready does not restart the shared
|
|
312
|
+
ADB server, approve Android's RSA dialog, or claim a distributed lock across
|
|
313
|
+
runner machines.
|
|
314
|
+
|
|
315
|
+
Do not expose a physical self-hosted runner to untrusted pull requests. Keep
|
|
316
|
+
the runner and its custom label scoped to trusted repositories or runner
|
|
317
|
+
groups, and keep the phone unlocked only when the project's assertions require
|
|
318
|
+
it. The example verifier is read-only and intentionally captures no screenshot
|
|
319
|
+
from a personal device.
|
|
320
|
+
|
|
321
|
+
### Gradle-owned virtual devices
|
|
322
|
+
|
|
323
|
+
When the Android build declares Gradle Managed Devices, keep lifecycle
|
|
324
|
+
ownership with Gradle instead of treating its transient emulator as an ADB
|
|
325
|
+
Ready target:
|
|
326
|
+
|
|
327
|
+
```bash
|
|
328
|
+
adb-ready test gradle
|
|
329
|
+
adb-ready test gradle :app:pixel2api35DebugAndroidTest --dry-run
|
|
330
|
+
adb-ready test gradle :app:pixel2api35DebugAndroidTest --software-rendering
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
ADB Ready preflights the exact task and normalizes fresh JUnit, HTML, shard,
|
|
334
|
+
and Gradle failure evidence without replacing the build's device definitions
|
|
335
|
+
or test DSL. See [Gradle Managed Devices](./gradle-managed-devices.md) for task
|
|
336
|
+
groups, sharding, outcomes, and the ownership boundary.
|
|
337
|
+
|
|
338
|
+
### Firebase-owned remote devices
|
|
339
|
+
|
|
340
|
+
Use Firebase Test Lab when the provider should own remote physical or virtual
|
|
341
|
+
targets while ADB Ready owns the deterministic invocation, outcome language,
|
|
342
|
+
and bounded evidence handoff:
|
|
343
|
+
|
|
344
|
+
```bash
|
|
345
|
+
adb-ready test firebase devices --project my-project
|
|
346
|
+
adb-ready test firebase instrumentation \
|
|
347
|
+
--project my-project \
|
|
348
|
+
--app app-debug.apk \
|
|
349
|
+
--test-apk app-debug-androidTest.apk \
|
|
350
|
+
--test-device model=Pixel2.arm,version=35 \
|
|
351
|
+
--dry-run --json
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
See [Firebase Test Lab](./firebase-test-lab.md) for live catalog policy,
|
|
355
|
+
provider-owned lifecycle, result buckets, normalized outcomes, and explicit
|
|
356
|
+
remote cancellation.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Shell completion
|
|
2
|
+
|
|
3
|
+
ADB Ready generates static tab-completion scripts for both `adb-ready` and its
|
|
4
|
+
short alias, `adbr`. Generation is instant and offline: it does not load project
|
|
5
|
+
configuration, start ADB, or inspect a device.
|
|
6
|
+
|
|
7
|
+
## Bash
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
mkdir -p ~/.local/share/bash-completion/completions
|
|
11
|
+
adb-ready completion bash > ~/.local/share/bash-completion/completions/adb-ready
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Start a new shell. If the user completion directory is not loaded by your Bash
|
|
15
|
+
installation, source the generated file from `~/.bashrc`.
|
|
16
|
+
|
|
17
|
+
## zsh
|
|
18
|
+
|
|
19
|
+
```zsh
|
|
20
|
+
mkdir -p ~/.zfunc
|
|
21
|
+
adb-ready completion zsh > ~/.zfunc/_adb-ready
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Add the directory before `compinit` in `~/.zshrc`:
|
|
25
|
+
|
|
26
|
+
```zsh
|
|
27
|
+
fpath=(~/.zfunc $fpath)
|
|
28
|
+
autoload -Uz compinit && compinit
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## fish
|
|
32
|
+
|
|
33
|
+
```fish
|
|
34
|
+
mkdir -p ~/.config/fish/completions
|
|
35
|
+
adb-ready completion fish > ~/.config/fish/completions/adb-ready.fish
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
fish loads the file automatically in new shell sessions.
|
|
39
|
+
|
|
40
|
+
## PowerShell
|
|
41
|
+
|
|
42
|
+
```powershell
|
|
43
|
+
New-Item -ItemType Directory -Force (Split-Path $PROFILE) | Out-Null
|
|
44
|
+
adb-ready completion powershell | Out-File -Append -Encoding utf8 $PROFILE
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Reload the profile with `. $PROFILE` or open a new PowerShell session.
|
|
48
|
+
|
|
49
|
+
## Nushell
|
|
50
|
+
|
|
51
|
+
```nu
|
|
52
|
+
mkdir ($nu.data-dir | path join "vendor" "autoload")
|
|
53
|
+
adb-ready completion nushell | save --force ($nu.data-dir | path join "vendor" "autoload" "adb-ready.nu")
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Nushell loads vendor autoload files in new sessions. The generated declarations
|
|
57
|
+
complete public commands while preserving ordinary file completion for command
|
|
58
|
+
arguments.
|
|
59
|
+
|
|
60
|
+
Regenerate the script after upgrading ADB Ready so newly added commands become
|
|
61
|
+
available to the shell.
|
package/docs/configuration.md
CHANGED
|
@@ -58,6 +58,7 @@ existing file unless `--force` is explicit. Use `--dry-run` first.
|
|
|
58
58
|
| `timeoutMs` | Default bounded operation timeout |
|
|
59
59
|
| `output` | Interactive, animation, color, and Unicode preferences |
|
|
60
60
|
| `targets.aliases` | Friendly name to exact ADB serial mapping |
|
|
61
|
+
| `targets.pools` | Named explicit target sets with bounded concurrency and queue policy |
|
|
61
62
|
| `dev` | Development-session configuration |
|
|
62
63
|
| `profiles` | Named, optionally inherited overrides |
|
|
63
64
|
|
|
@@ -81,6 +82,11 @@ existing file unless `--force` is explicit. Use `--dry-run` first.
|
|
|
81
82
|
Unknown keys and invalid nested values fail validation rather than being
|
|
82
83
|
silently ignored.
|
|
83
84
|
|
|
85
|
+
Target pools accept typed `adb`, `avd`, `remote-adb`, or `firebase` members.
|
|
86
|
+
Every pool requires an explicit `maxConcurrency`; member IDs and resource
|
|
87
|
+
identities must be unique. See [Target pools and fan-out](./target-pools.md) for
|
|
88
|
+
the complete schema, execution semantics, and trust boundaries.
|
|
89
|
+
|
|
84
90
|
`init` detects and writes `packageManager` only for Expo, React Native, and
|
|
85
91
|
Capacitor presets, where it selects the project CLI. Flutter and native Gradle
|
|
86
92
|
use their own launchers, so an unrelated package-manager executable available
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Firebase Test Lab
|
|
2
|
+
|
|
3
|
+
Use this workflow when Firebase should own the remote Android targets. ADB
|
|
4
|
+
Ready validates exact dimensions against the live catalog, starts one bounded
|
|
5
|
+
instrumentation or Robo matrix through `gcloud`, normalizes its outcome, and
|
|
6
|
+
keeps local evidence. It does not create projects, manage billing, provision
|
|
7
|
+
credentials, or replace Firebase's test formats.
|
|
8
|
+
|
|
9
|
+
## Prerequisites
|
|
10
|
+
|
|
11
|
+
Install the current [Google Cloud CLI](https://cloud.google.com/sdk/docs/install),
|
|
12
|
+
authenticate it in the surrounding developer or CI environment, and enable
|
|
13
|
+
Firebase Test Lab for the selected Google Cloud project. Credentials remain in
|
|
14
|
+
Google's credential store; ADB Ready never writes access tokens into config,
|
|
15
|
+
output, or evidence.
|
|
16
|
+
|
|
17
|
+
Inspect the authenticated live catalog before choosing a matrix:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
adb-ready test firebase devices --project my-project
|
|
21
|
+
adb-ready test firebase devices --project my-project --json
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Catalog output joins each model to its supported Android versions and reports
|
|
25
|
+
form, form factor, capacity, and provider tags. A requested unavailable,
|
|
26
|
+
inaccessible, deprecated, reduced-stability, zero-capacity, or low-capacity
|
|
27
|
+
dimension fails before artifact upload. Deprecated, reduced-stability, and
|
|
28
|
+
low-capacity choices require their matching explicit `--allow-*` policy.
|
|
29
|
+
|
|
30
|
+
## Instrumentation
|
|
31
|
+
|
|
32
|
+
Preview the exact direct `gcloud` invocation first:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
adb-ready test firebase instrumentation \
|
|
36
|
+
--project my-project \
|
|
37
|
+
--app app/build/outputs/apk/debug/app-debug.apk \
|
|
38
|
+
--test-apk app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk \
|
|
39
|
+
--test-device model=Pixel2.arm,version=35,locale=en,orientation=portrait \
|
|
40
|
+
--dry-run --json
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Remove `--dry-run` to create the matrix. Repeat `--test-device` for additional
|
|
44
|
+
explicit dimensions. Local paths and private `gs://bucket/object` artifact
|
|
45
|
+
references are supported; signed URLs are rejected so credentials cannot be
|
|
46
|
+
retained accidentally.
|
|
47
|
+
|
|
48
|
+
## Robo
|
|
49
|
+
|
|
50
|
+
Robo needs the app artifact but no instrumentation APK:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
adb-ready test firebase robo \
|
|
54
|
+
--project my-project \
|
|
55
|
+
--app app-debug.apk \
|
|
56
|
+
--test-device model=Pixel2.arm,version=35
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`--test-timeout 10m` controls the provider-side timeout for each execution.
|
|
60
|
+
`--run-timeout 30m` bounds only ADB Ready's local observation.
|
|
61
|
+
|
|
62
|
+
## Results and evidence
|
|
63
|
+
|
|
64
|
+
For deterministic CI retention, use a bucket your job can read and write:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
adb-ready test firebase instrumentation \
|
|
68
|
+
--project my-project \
|
|
69
|
+
--app app-debug.apk \
|
|
70
|
+
--test-apk app-debug-androidTest.apk \
|
|
71
|
+
--test-device model=Pixel2.arm,version=35 \
|
|
72
|
+
--results-bucket gs://my-test-results \
|
|
73
|
+
--results-dir ci/$GITHUB_RUN_ID
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
ADB Ready always retains redacted `gcloud` output and the structured result
|
|
77
|
+
under `.adb-ready/artifacts/firebase-<run-id>/`. With an explicit result bucket,
|
|
78
|
+
it also lists only that exact prefix and downloads a bounded allowlist of native
|
|
79
|
+
JUnit, HTML, JSON, log, screenshot, video, coverage, and protobuf artifacts:
|
|
80
|
+
|
|
81
|
+
- at most 100 provider files;
|
|
82
|
+
- at most 20 MiB per file;
|
|
83
|
+
- at most 50 MiB total;
|
|
84
|
+
- exact post-download size verification; and
|
|
85
|
+
- a local `provider-files.json` source manifest.
|
|
86
|
+
|
|
87
|
+
The structured result reports `complete`, `unavailable`, `remote-running`, or
|
|
88
|
+
`not-configured` evidence collection. Failure to copy requested provider
|
|
89
|
+
evidence is a warning alongside the original test outcome; it never rewrites a
|
|
90
|
+
test assertion into a false pass or a different provider outcome.
|
|
91
|
+
|
|
92
|
+
Without an explicit bucket, the Firebase console URL remains the provider
|
|
93
|
+
result reference and only local normalized evidence is copied.
|
|
94
|
+
|
|
95
|
+
## Outcomes and cancellation
|
|
96
|
+
|
|
97
|
+
ADB Ready preserves the documented `gcloud firebase test android run` result
|
|
98
|
+
classes instead of flattening them:
|
|
99
|
+
|
|
100
|
+
- `passed`;
|
|
101
|
+
- `flaky` — provider roll-up succeeded but at least one test was flaky;
|
|
102
|
+
- `assertion-failed`;
|
|
103
|
+
- `inconclusive`;
|
|
104
|
+
- `unsupported`;
|
|
105
|
+
- `cancelled`;
|
|
106
|
+
- `infrastructure-failed`;
|
|
107
|
+
- `auth-failed`; and
|
|
108
|
+
- local `observation-timed-out` or `observation-stopped`.
|
|
109
|
+
|
|
110
|
+
Stopping or timing out local observation intentionally leaves an identified
|
|
111
|
+
remote matrix running. Cancel exactly one matrix with a separate explicit
|
|
112
|
+
action:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
adb-ready test firebase cancel MATRIX_ID --project my-project --dry-run
|
|
116
|
+
adb-ready test firebase cancel MATRIX_ID --project my-project
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Cancellation obtains a short-lived access token from the authenticated
|
|
120
|
+
`gcloud` process in memory and calls the official Testing API. The token is not
|
|
121
|
+
stored or printed.
|
|
122
|
+
|
|
123
|
+
See Firebase's current [Android CLI guide](https://firebase.google.com/docs/test-lab/android/command-line),
|
|
124
|
+
[available-device guidance](https://firebase.google.com/docs/test-lab/android/available-testing-devices),
|
|
125
|
+
and [result documentation](https://firebase.google.com/docs/test-lab/android/analyzing-results)
|
|
126
|
+
for provider setup, billing, quotas, and native result semantics.
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Gradle Managed Devices
|
|
2
|
+
|
|
3
|
+
Use this workflow when the Android build already declares virtual devices or
|
|
4
|
+
device groups in Gradle. Gradle remains the lifecycle owner: it provisions the
|
|
5
|
+
emulator, installs the app and tests, applies sharding, runs instrumentation,
|
|
6
|
+
and tears the target down. ADB Ready does not select, lease, or send commands to
|
|
7
|
+
that transient emulator.
|
|
8
|
+
|
|
9
|
+
## Discover declared tasks
|
|
10
|
+
|
|
11
|
+
Run discovery from the Gradle project root:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
adb-ready test gradle
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
ADB Ready invokes the checked-in `gradlew` or `android/gradlew` Wrapper and
|
|
18
|
+
lists only task descriptions that identify a managed device or device group.
|
|
19
|
+
If the Wrapper lives elsewhere, pass it explicitly:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
adb-ready test gradle --gradle tools/gradlew
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Task names belong to the project. Typical Android Gradle Plugin names resemble
|
|
26
|
+
`pixel2api35DebugAndroidTest` and
|
|
27
|
+
`phoneAndTabletGroupDebugAndroidTest`; ADB Ready does not invent a device,
|
|
28
|
+
variant, or group name.
|
|
29
|
+
|
|
30
|
+
## Preview and run one task
|
|
31
|
+
|
|
32
|
+
Preview the exact direct process invocation without starting Gradle:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
adb-ready test gradle :app:pixel2api35DebugAndroidTest --dry-run --json
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Then execute the same bounded task:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
adb-ready test gradle :app:pixel2api35DebugAndroidTest --run-timeout 20m
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Before execution, ADB Ready asks Gradle to resolve that exact task. A missing
|
|
45
|
+
task fails before test infrastructure starts. The task is passed directly to
|
|
46
|
+
the Wrapper without a shell.
|
|
47
|
+
|
|
48
|
+
## Groups, sharding, and server rendering
|
|
49
|
+
|
|
50
|
+
A declared group task runs through the same boundary:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
adb-ready test gradle :app:phoneAndTabletGroupDebugAndroidTest
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Request Gradle's managed-device sharding property when the build and Android
|
|
57
|
+
Gradle Plugin support it:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
adb-ready test gradle :app:pixel2api35DebugAndroidTest --shards 4
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
On a headless host, opt into Gradle's documented SwiftShader property:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
adb-ready test gradle :app:pixel2api35DebugAndroidTest --software-rendering
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
ADB Ready passes these properties for the current invocation. It never edits
|
|
70
|
+
Gradle files, creates SDK components, or changes a project's declared devices.
|
|
71
|
+
|
|
72
|
+
## Results and evidence
|
|
73
|
+
|
|
74
|
+
After execution, ADB Ready reads native files from the Android Gradle Plugin
|
|
75
|
+
managed-device result and report directories. It retains bounded XML,
|
|
76
|
+
HTML, JSON, logs, text, screenshots, and video under:
|
|
77
|
+
|
|
78
|
+
```text
|
|
79
|
+
.adb-ready/artifacts/gradle-managed-<run-id>/
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Machine output keeps these outcomes distinct:
|
|
83
|
+
|
|
84
|
+
- `passed` — Gradle exited successfully and retained JUnit has no failures;
|
|
85
|
+
- `assertion-failed` — fresh JUnit reports a failed or errored test;
|
|
86
|
+
- `infrastructure-failed` — Gradle could not complete provisioning or execution
|
|
87
|
+
and no test assertion explains the failure;
|
|
88
|
+
- `timed-out` — the configured finite timeout expired;
|
|
89
|
+
- `cancelled` — the caller interrupted the task;
|
|
90
|
+
- `GRADLE_MANAGED_TASK_NOT_FOUND` — exact task preflight failed.
|
|
91
|
+
|
|
92
|
+
The original Gradle result and report trees remain the source artifacts. The
|
|
93
|
+
ADB Ready copy is bounded, redacted where textual, and convenient for CI upload
|
|
94
|
+
or an agent. Failed tasks can only classify assertions from files written by
|
|
95
|
+
that execution. A successful up-to-date Gradle task may retain the output that
|
|
96
|
+
Gradle validated from its cache, explicitly marked with `gradle-cache`
|
|
97
|
+
provenance.
|
|
98
|
+
|
|
99
|
+
## Responsibility boundary
|
|
100
|
+
|
|
101
|
+
Use `adb-ready test gradle` for Gradle-owned virtual devices. Use
|
|
102
|
+
`adb-ready run` when ADB Ready must own one already visible ADB target, prepare
|
|
103
|
+
ports and a development service, run a finite verifier, and clean only its own
|
|
104
|
+
resources. Connected-device tasks therefore remain under `run`; they are not
|
|
105
|
+
misrepresented as Gradle Managed Devices.
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# Target pools and fan-out
|
|
2
|
+
|
|
3
|
+
Use a target pool when the same bounded verification must run against an
|
|
4
|
+
explicit set of Android targets. Pool mode is opt-in. A normal `adb-ready run`
|
|
5
|
+
still selects exactly one target.
|
|
6
|
+
|
|
7
|
+
Every acquired member receives its own single-target session, target lease,
|
|
8
|
+
verifier result, cleanup, and evidence bundle. The pool result aggregates those
|
|
9
|
+
unchanged member envelopes in declaration order.
|
|
10
|
+
|
|
11
|
+
## Declare a local pool
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"$schema": "./node_modules/adb-ready/schema/config-v1.schema.json",
|
|
16
|
+
"version": 1,
|
|
17
|
+
"targets": {
|
|
18
|
+
"pools": {
|
|
19
|
+
"smoke": {
|
|
20
|
+
"maxConcurrency": 2,
|
|
21
|
+
"failFast": false,
|
|
22
|
+
"leaseWaitMs": 30000,
|
|
23
|
+
"members": [
|
|
24
|
+
{ "id": "desk", "kind": "adb", "serial": "R3CT..." },
|
|
25
|
+
{ "id": "api36", "kind": "avd", "name": "Pixel_9_API_36" },
|
|
26
|
+
{
|
|
27
|
+
"id": "lab",
|
|
28
|
+
"kind": "remote-adb",
|
|
29
|
+
"host": "android-lab.internal",
|
|
30
|
+
"port": 5037,
|
|
31
|
+
"serial": "10.20.0.15:5555"
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Run the same verifier on every member:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
adb-ready run --pool smoke -- npm run test:e2e
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Preview every member without inspecting ADB, starting an AVD, or running the
|
|
47
|
+
verifier:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
adb-ready run --pool smoke --dry-run --json -- npm run test:e2e
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The pool owns concurrency policy; it never infers an unbounded worker count.
|
|
54
|
+
Override it for one invocation only when the CI runner has known capacity:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
adb-ready run --pool smoke --max-concurrency 1 --fail-fast \
|
|
58
|
+
--lease-wait 45s -- npm run test:e2e
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Member kinds
|
|
62
|
+
|
|
63
|
+
| Kind | Required fields | Ownership |
|
|
64
|
+
| --- | --- | --- |
|
|
65
|
+
| `adb` | `id`, exact `serial` | Uses an already ADB-visible target. |
|
|
66
|
+
| `avd` | `id`, exact existing AVD `name` | Reuses or starts that AVD; stops only an emulator process started by this run. |
|
|
67
|
+
| `remote-adb` | `id`, `host`, exact `serial`; optional `port` | Uses the explicit ADB server without changing the global local server. |
|
|
68
|
+
| `firebase` | `id`, `model`, `version`; optional `locale`, `orientation` | Firebase owns the remote target and lifecycle. Use only with `test firebase`. |
|
|
69
|
+
|
|
70
|
+
Member IDs and resource identities must be unique inside a pool. Members are
|
|
71
|
+
required by default. Set `"required": false` only when that dimension is truly
|
|
72
|
+
informational; an optional failure remains visible but does not fail the
|
|
73
|
+
aggregate.
|
|
74
|
+
|
|
75
|
+
## Firebase dimensions
|
|
76
|
+
|
|
77
|
+
A Firebase-only pool submits one independently observable matrix per declared
|
|
78
|
+
dimension. This gives every dimension a stable member result and lets ADB Ready
|
|
79
|
+
bound submission concurrency.
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
{
|
|
83
|
+
"version": 1,
|
|
84
|
+
"targets": {
|
|
85
|
+
"pools": {
|
|
86
|
+
"firebase-smoke": {
|
|
87
|
+
"maxConcurrency": 2,
|
|
88
|
+
"failFast": true,
|
|
89
|
+
"members": [
|
|
90
|
+
{ "id": "pixel-api35", "kind": "firebase", "model": "akita", "version": "35" },
|
|
91
|
+
{ "id": "tablet-api34", "kind": "firebase", "model": "tangorpro", "version": "34" }
|
|
92
|
+
]
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
adb-ready test firebase instrumentation \
|
|
101
|
+
--pool firebase-smoke \
|
|
102
|
+
--project my-project \
|
|
103
|
+
--app app-debug.apk \
|
|
104
|
+
--test-apk app-debug-androidTest.apk
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Dimensions are checked against the live Firebase catalog before upload. With
|
|
108
|
+
`failFast`, ADB Ready stops submitting queued dimensions after a required
|
|
109
|
+
failure. It does not cancel matrices already running remotely. Use
|
|
110
|
+
`adb-ready test firebase cancel` for an intentional provider cancellation.
|
|
111
|
+
|
|
112
|
+
## Queueing and leases
|
|
113
|
+
|
|
114
|
+
ADB Ready serializes contending work with an owner-recorded, heartbeating lease.
|
|
115
|
+
`leaseWaitMs` bounds how long a pool member waits; cancellation exits the queue
|
|
116
|
+
without taking ownership. Expired leases and leases owned by a dead process on
|
|
117
|
+
the same host are recovered conservatively.
|
|
118
|
+
|
|
119
|
+
The built-in coordination backend is a per-user filesystem on one host. It is
|
|
120
|
+
not a distributed lock. CI jobs on different machines need runner-level
|
|
121
|
+
routing or another explicit external coordination system. ADB Ready never
|
|
122
|
+
infers cross-host ownership.
|
|
123
|
+
|
|
124
|
+
An explicit remote ADB server is also a trust boundary: its socket is not
|
|
125
|
+
encrypted by ADB Ready. Protect it with a trusted private network, VPN, SSH
|
|
126
|
+
tunnel, or equivalent transport; never expose port 5037 to an untrusted
|
|
127
|
+
network.
|
|
128
|
+
|
|
129
|
+
## Aggregate result
|
|
130
|
+
|
|
131
|
+
Human output shows the status of every member. JSON and NDJSON preserve every
|
|
132
|
+
nested result envelope, including its command ID, structured problems,
|
|
133
|
+
timestamps, and evidence path. The aggregate cannot report success when any
|
|
134
|
+
required member failed, disappeared, was cancelled, or never started.
|
|
135
|
+
|
|
136
|
+
Useful automation fields:
|
|
137
|
+
|
|
138
|
+
```text
|
|
139
|
+
data.pool
|
|
140
|
+
data.maxConcurrency
|
|
141
|
+
data.failFast
|
|
142
|
+
data.coordination
|
|
143
|
+
data.members[].id
|
|
144
|
+
data.members[].status
|
|
145
|
+
data.members[].exitCode
|
|
146
|
+
data.members[].result
|
|
147
|
+
data.summary
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Pool configuration is declarative data. It cannot add executable hooks or
|
|
151
|
+
shell fragments, and every verifier continues to use direct argv execution.
|
|
@@ -96,6 +96,21 @@ This is useful for WSL, containers, VMs, SSH-forwarded workstations, and device
|
|
|
96
96
|
labs. ADB Ready does not start, kill, or reconfigure that shared server
|
|
97
97
|
implicitly.
|
|
98
98
|
|
|
99
|
+
Before every command sent through an explicit `--adb-host` or `--adb-port`, ADB
|
|
100
|
+
Ready opens a bounded read-only connection and requests only `host:version`.
|
|
101
|
+
The real `adb` process starts only when the server protocol matches the local
|
|
102
|
+
client. This matters because the upstream ADB client automatically sends
|
|
103
|
+
`host:kill` when it encounters a mismatched server version (see the
|
|
104
|
+
[AOSP ADB client implementation](https://android.googlesource.com/platform/packages/modules/adb/+/refs/heads/main/client/adb_client.cpp)).
|
|
105
|
+
ADB Ready instead returns `ADB_REMOTE_SERVER_PROTOCOL_MISMATCH` and leaves the
|
|
106
|
+
shared server untouched.
|
|
107
|
+
|
|
108
|
+
The preflight also distinguishes an unreachable route, timeout, cancellation,
|
|
109
|
+
and a non-ADB response. It is repeated before each command so replacement of a
|
|
110
|
+
server during a long session fails closed. This is a narrow safety handshake,
|
|
111
|
+
not a replacement ADB transport; all device operations still use the selected
|
|
112
|
+
`adb` executable.
|
|
113
|
+
|
|
99
114
|
## Network limitations
|
|
100
115
|
|
|
101
116
|
Wireless discovery and connection can be blocked by guest Wi-Fi, client
|
|
@@ -110,6 +125,12 @@ adb-ready doctor --verbose
|
|
|
110
125
|
adb-ready devices
|
|
111
126
|
```
|
|
112
127
|
|
|
128
|
+
For WSL, a container, VM, or remote runner, first verify that its network
|
|
129
|
+
namespace can reach the exact protected ADB host and port. A successful DNS
|
|
130
|
+
lookup or mDNS discovery does not prove that the TCP route is usable. ADB Ready
|
|
131
|
+
reports this as `ADB_REMOTE_SERVER_UNREACHABLE` rather than an empty target
|
|
132
|
+
list.
|
|
133
|
+
|
|
113
134
|
If discovery is unavailable but the device shows a reachable connection
|
|
114
135
|
endpoint, pass it explicitly. Do not assume port `5555`; modern Wireless
|
|
115
136
|
debugging ports are dynamic.
|
package/docs/troubleshooting.md
CHANGED
|
@@ -21,6 +21,9 @@ adb-ready context --since 5m --only problems,recovery,logs
|
|
|
21
21
|
| `ADB_NOT_FOUND` | No usable ADB executable was resolved | Install Platform-Tools or pass `--adb PATH` |
|
|
22
22
|
| `ADB_SERVER_UNAVAILABLE` | The selected local or remote server could not be queried | Check the configured host/port and run `adb start-server` explicitly if appropriate |
|
|
23
23
|
| `ADB_VERSION_MISMATCH` | Client and server report incompatible versions | Align Platform-Tools versions; review before restarting the shared server |
|
|
24
|
+
| `ADB_REMOTE_SERVER_UNREACHABLE` | The explicit server socket has no usable route | Check WSL/container/VM/VPN/firewall/tunnel routing; do not expose port 5037 publicly |
|
|
25
|
+
| `ADB_REMOTE_SERVER_PROTOCOL_MISMATCH` | Remote and local ADB protocols differ | Align Platform-Tools deliberately; ADB Ready will not let upstream ADB kill the shared server |
|
|
26
|
+
| `ADB_REMOTE_SERVER_INVALID_RESPONSE` | The endpoint or local client could not complete the read-only protocol preflight | Verify the host, port, tunnel destination, and local Platform-Tools installation |
|
|
24
27
|
| `TARGET_UNAUTHORIZED` | Android has not authorized this host | Unlock the device and accept its RSA debugging prompt |
|
|
25
28
|
| `TARGET_NO_PERMISSIONS` | The host cannot access the USB device | Fix host USB permissions or rules, then reconnect |
|
|
26
29
|
| `TARGET_OFFLINE` | ADB knows the transport but it is not ready | Check cable/network state and retry `devices` |
|
package/examples/README.md
CHANGED
|
@@ -15,8 +15,14 @@ adb-ready dev --dry-run
|
|
|
15
15
|
- [`flutter/adb-ready.config.json`](./flutter/adb-ready.config.json)
|
|
16
16
|
- [`capacitor/adb-ready.config.json`](./capacitor/adb-ready.config.json)
|
|
17
17
|
- [`custom/adb-ready.config.json`](./custom/adb-ready.config.json)
|
|
18
|
+
- [`ci-emulator/`](./ci-emulator/) — maintained GitHub-hosted emulator
|
|
19
|
+
acceptance with a finite run and retained failure evidence
|
|
20
|
+
- [`ci-physical/`](./ci-physical/) — manual self-hosted physical-device job
|
|
21
|
+
with explicit serial selection, host-local leasing, and bounded evidence
|
|
18
22
|
- [`automation/README.md`](./automation/README.md) — one finite AVD, deployment,
|
|
19
23
|
verifier, evidence, and cleanup job
|
|
24
|
+
- [`target-pools/`](./target-pools/) — bounded fan-out across explicit local,
|
|
25
|
+
AVD, remote-ADB, or Firebase members
|
|
20
26
|
|
|
21
27
|
Prefer `adb-ready init` when starting from an existing detected project. Add
|
|
22
28
|
only the ports, hooks, and retention rules that the project genuinely needs.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# GitHub-hosted Android emulator
|
|
2
|
+
|
|
3
|
+
This fixture powers ADB Ready's maintained emulator acceptance workflow. It
|
|
4
|
+
demonstrates the ownership boundary used in ordinary CI:
|
|
5
|
+
|
|
6
|
+
1. the runner provisions and owns one Android emulator;
|
|
7
|
+
2. ADB Ready binds a finite run to its exact serial;
|
|
8
|
+
3. the fixture verifies Android boot and identity, opens Settings, and captures
|
|
9
|
+
native evidence; and
|
|
10
|
+
4. ADB Ready retains normalized NDJSON, JUnit, screenshot, window, and manifest
|
|
11
|
+
evidence before the runner tears its emulator down.
|
|
12
|
+
|
|
13
|
+
The workflow is [`android-emulator.yml`](../../.github/workflows/android-emulator.yml).
|
|
14
|
+
Every external Action is pinned to a full commit. The job uses no repository
|
|
15
|
+
secret and uploads evidence with `if: always()`.
|
|
16
|
+
|
|
17
|
+
Do not copy the fixture's custom development process into an application. Keep
|
|
18
|
+
your real project command and readiness assertions, then use the same bounded
|
|
19
|
+
shape:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx adb-ready run \
|
|
23
|
+
--device emulator-5554 \
|
|
24
|
+
--run-timeout 10m \
|
|
25
|
+
--json \
|
|
26
|
+
--non-interactive \
|
|
27
|
+
-- npm run test:e2e
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
ADB Ready does not implicitly create SDKs or AVDs. If another workflow layer
|
|
31
|
+
created the emulator, ADB Ready attaches without claiming ownership and leaves
|
|
32
|
+
emulator teardown to that layer.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../schema/config-v1.schema.json",
|
|
3
|
+
"version": 1,
|
|
4
|
+
"dev": {
|
|
5
|
+
"preset": "custom",
|
|
6
|
+
"command": {
|
|
7
|
+
"executable": "node",
|
|
8
|
+
"args": ["examples/ci-emulator/dev-service.mjs"]
|
|
9
|
+
},
|
|
10
|
+
"reversePorts": [],
|
|
11
|
+
"logs": false,
|
|
12
|
+
"cleanupPorts": true,
|
|
13
|
+
"watch": true,
|
|
14
|
+
"ready": {
|
|
15
|
+
"timeoutMs": 60000,
|
|
16
|
+
"pollIntervalMs": 1000,
|
|
17
|
+
"all": [{ "kind": "boot" }, { "kind": "unlocked" }]
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|