xcodebuild-axi 0.1.6 → 0.1.8
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 +57 -0
- package/README.md +98 -2
- package/dist/src/args.d.ts +11 -0
- package/dist/src/args.js +30 -0
- package/dist/src/args.js.map +1 -1
- package/dist/src/cli.d.ts +8 -0
- package/dist/src/cli.js +53 -22
- package/dist/src/cli.js.map +1 -1
- package/dist/src/commands/analyze.d.ts +2 -0
- package/dist/src/commands/analyze.js +3 -1
- package/dist/src/commands/analyze.js.map +1 -1
- package/dist/src/commands/archive.d.ts +1 -0
- package/dist/src/commands/archive.js +6 -2
- package/dist/src/commands/archive.js.map +1 -1
- package/dist/src/commands/build.d.ts +1 -0
- package/dist/src/commands/build.js +2 -2
- package/dist/src/commands/build.js.map +1 -1
- package/dist/src/commands/clean.d.ts +1 -0
- package/dist/src/commands/clean.js +6 -2
- package/dist/src/commands/clean.js.map +1 -1
- package/dist/src/commands/coverage.d.ts +1 -0
- package/dist/src/commands/coverage.js +7 -2
- package/dist/src/commands/coverage.js.map +1 -1
- package/dist/src/commands/destinations.d.ts +1 -0
- package/dist/src/commands/destinations.js +6 -2
- package/dist/src/commands/destinations.js.map +1 -1
- package/dist/src/commands/export.d.ts +2 -0
- package/dist/src/commands/export.js +11 -5
- package/dist/src/commands/export.js.map +1 -1
- package/dist/src/commands/find.d.ts +1 -0
- package/dist/src/commands/find.js +2 -2
- package/dist/src/commands/find.js.map +1 -1
- package/dist/src/commands/info.d.ts +1 -0
- package/dist/src/commands/info.js +2 -2
- package/dist/src/commands/info.js.map +1 -1
- package/dist/src/commands/localize.d.ts +1 -0
- package/dist/src/commands/localize.js +2 -2
- package/dist/src/commands/localize.js.map +1 -1
- package/dist/src/commands/migrate.d.ts +1 -0
- package/dist/src/commands/migrate.js +2 -2
- package/dist/src/commands/migrate.js.map +1 -1
- package/dist/src/commands/packages.d.ts +1 -0
- package/dist/src/commands/packages.js +7 -2
- package/dist/src/commands/packages.js.map +1 -1
- package/dist/src/commands/platforms.d.ts +1 -0
- package/dist/src/commands/platforms.js +2 -2
- package/dist/src/commands/platforms.js.map +1 -1
- package/dist/src/commands/result.d.ts +1 -0
- package/dist/src/commands/result.js +7 -2
- package/dist/src/commands/result.js.map +1 -1
- package/dist/src/commands/schemes.d.ts +1 -0
- package/dist/src/commands/schemes.js +2 -1
- package/dist/src/commands/schemes.js.map +1 -1
- package/dist/src/commands/settings.d.ts +1 -0
- package/dist/src/commands/settings.js +2 -2
- package/dist/src/commands/settings.js.map +1 -1
- package/dist/src/commands/setup.d.ts +1 -0
- package/dist/src/commands/setup.js +2 -2
- package/dist/src/commands/setup.js.map +1 -1
- package/dist/src/commands/sim.d.ts +1 -0
- package/dist/src/commands/sim.js +2 -2
- package/dist/src/commands/sim.js.map +1 -1
- package/dist/src/commands/test.d.ts +1 -0
- package/dist/src/commands/test.js +2 -2
- package/dist/src/commands/test.js.map +1 -1
- package/dist/src/commands/testplans.d.ts +1 -0
- package/dist/src/commands/testplans.js +2 -1
- package/dist/src/commands/testplans.js.map +1 -1
- package/dist/src/commands/tests.d.ts +1 -0
- package/dist/src/commands/tests.js +2 -2
- package/dist/src/commands/tests.js.map +1 -1
- package/dist/src/commands/xcframework.d.ts +19 -1
- package/dist/src/commands/xcframework.js +116 -27
- package/dist/src/commands/xcframework.js.map +1 -1
- package/dist/src/surface.d.ts +133 -1
- package/dist/src/surface.js +712 -265
- package/dist/src/surface.js.map +1 -1
- package/package.json +1 -1
package/dist/src/surface.js
CHANGED
|
@@ -6,6 +6,20 @@
|
|
|
6
6
|
* rather than inferred: every option `xcodebuild -help` prints is classified,
|
|
7
7
|
* and `npm run coverage -- --check` fails if a new Xcode adds one this file
|
|
8
8
|
* has never heard of.
|
|
9
|
+
*
|
|
10
|
+
* "Covered" is asked along four axes, because for a long time it was only
|
|
11
|
+
* asked along the first and the misses all landed on the other three:
|
|
12
|
+
*
|
|
13
|
+
* 1. **Options** — does any command reach this option at all.
|
|
14
|
+
* 2. **Reach** — does every command xcodebuild accepts it on reach it. An
|
|
15
|
+
* option exposed on `build` and missing from `settings` is not covered for
|
|
16
|
+
* anyone asking `settings`, and nothing used to say so.
|
|
17
|
+
* 3. **Forms and sub-surfaces** — the options behind an option: the keys of
|
|
18
|
+
* `-exportOptionsPlist`, the arguments of `-create-xcframework`, the second
|
|
19
|
+
* modes that `-help` documents only inside a usage line.
|
|
20
|
+
* 4. **Companion tools** — `xcresulttool`, `xccov`, `simctl`. Not xcodebuild,
|
|
21
|
+
* so not in its headline number, but this tool wraps them and an agent that
|
|
22
|
+
* has to shell out to one directly has dropped back down.
|
|
9
23
|
*/
|
|
10
24
|
/**
|
|
11
25
|
* The Xcode whose `xcodebuild -help` this map was written against.
|
|
@@ -18,249 +32,226 @@
|
|
|
18
32
|
* mismatch here and merely reports one elsewhere.
|
|
19
33
|
*/
|
|
20
34
|
export const AUTHORED_AGAINST = "27.0";
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
"
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
},
|
|
77
|
-
"-disableAutomaticPackageResolution": {
|
|
78
|
-
status: "exposed",
|
|
79
|
-
via: "build --no-auto-resolve",
|
|
80
|
-
},
|
|
81
|
-
"-disablePackageRepositoryCache": {
|
|
82
|
-
status: "exposed",
|
|
83
|
-
via: "build --no-package-cache",
|
|
84
|
-
},
|
|
85
|
-
"-downloadAllPlatforms": {
|
|
86
|
-
status: "exposed",
|
|
87
|
-
via: "platforms download --all",
|
|
88
|
-
},
|
|
89
|
-
"-downloadComponent": {
|
|
90
|
-
status: "exposed",
|
|
91
|
-
via: "platforms component download",
|
|
92
|
-
},
|
|
93
|
-
"-downloadPlatform": { status: "exposed", via: "platforms download" },
|
|
94
|
-
"-enableAddressSanitizer": {
|
|
95
|
-
status: "exposed",
|
|
96
|
-
via: "build --sanitizer address",
|
|
97
|
-
},
|
|
98
|
-
"-enableCodeCoverage": { status: "exposed", via: "test --coverage" },
|
|
99
|
-
"-enableCodesizeProfile": { status: "exposed", via: "build --codesize" },
|
|
100
|
-
"-enablePerformanceTestsDiagnostics": {
|
|
101
|
-
status: "exposed",
|
|
102
|
-
via: "test --perf-diagnostics",
|
|
103
|
-
},
|
|
104
|
-
"-enableThreadSanitizer": {
|
|
105
|
-
status: "exposed",
|
|
106
|
-
via: "build --sanitizer thread",
|
|
107
|
-
},
|
|
108
|
-
"-enableUndefinedBehaviorSanitizer": {
|
|
109
|
-
status: "exposed",
|
|
110
|
-
via: "build --sanitizer undefined",
|
|
111
|
-
},
|
|
112
|
-
"-enumerate-tests": { status: "exposed", via: "tests" },
|
|
113
|
-
"-exportArchive": { status: "exposed", via: "export" },
|
|
114
|
-
"-exportLanguage": { status: "exposed", via: "localize export --language" },
|
|
115
|
-
"-exportLocalizations": { status: "exposed", via: "localize export" },
|
|
116
|
-
"-exportNotarizedApp": { status: "exposed", via: "export --notarized" },
|
|
117
|
-
"-exportOptionsPlist": { status: "exposed", via: "export --options" },
|
|
118
|
-
"-exportPath": { status: "exposed", via: "export --output" },
|
|
119
|
-
"-find-executable": { status: "exposed", via: "find" },
|
|
120
|
-
"-find-library": { status: "exposed", via: "find --library" },
|
|
121
|
-
"-hideShellScriptEnvironment": {
|
|
122
|
-
status: "exposed",
|
|
123
|
-
via: "build --hide-script-env",
|
|
124
|
-
},
|
|
125
|
-
"-importComponent": { status: "exposed", via: "platforms component import" },
|
|
126
|
-
"-importLocalizations": { status: "exposed", via: "localize import" },
|
|
127
|
-
"-importPath": {
|
|
128
|
-
status: "exposed",
|
|
129
|
-
via: "platforms component import --import-path",
|
|
130
|
-
},
|
|
131
|
-
"-importPlatform": { status: "exposed", via: "platforms import" },
|
|
132
|
-
"-jobs": { status: "exposed", via: "build --jobs" },
|
|
133
|
-
"-list": { status: "exposed", via: "schemes" },
|
|
134
|
-
"-localizationPath": { status: "exposed", via: "localize --path" },
|
|
135
|
-
"-maximum-concurrent-test-device-destinations": {
|
|
136
|
-
status: "exposed",
|
|
137
|
-
via: "test --max-device-destinations",
|
|
138
|
-
},
|
|
139
|
-
"-maximum-concurrent-test-simulator-destinations": {
|
|
140
|
-
status: "exposed",
|
|
141
|
-
via: "test --max-sim-destinations",
|
|
142
|
-
},
|
|
143
|
-
"-maximum-parallel-testing-workers": {
|
|
144
|
-
status: "exposed",
|
|
145
|
-
via: "test --max-workers",
|
|
146
|
-
},
|
|
147
|
-
"-maximum-test-execution-time-allowance": {
|
|
148
|
-
status: "exposed",
|
|
149
|
-
via: "test --test-timeout",
|
|
150
|
-
},
|
|
151
|
-
"-modelCode": {
|
|
152
|
-
status: "exposed",
|
|
153
|
-
via: "platforms device-support --model-code",
|
|
154
|
-
},
|
|
155
|
-
"-only-test-configuration": {
|
|
156
|
-
status: "exposed",
|
|
157
|
-
via: "test --only-configuration",
|
|
158
|
-
},
|
|
159
|
-
"-only-testing": { status: "exposed", via: "test --only" },
|
|
160
|
-
"-onlyUsePackageVersionsFromResolvedFile": {
|
|
161
|
-
status: "exposed",
|
|
162
|
-
via: "packages --offline",
|
|
163
|
-
},
|
|
164
|
-
"-osVersion": {
|
|
165
|
-
status: "exposed",
|
|
166
|
-
via: "platforms device-support --os-version",
|
|
167
|
-
},
|
|
168
|
-
"-packageAuthorizationProvider": {
|
|
169
|
-
status: "exposed",
|
|
170
|
-
via: "packages --package-auth",
|
|
171
|
-
},
|
|
172
|
-
"-packageCachePath": { status: "exposed", via: "packages --package-cache" },
|
|
173
|
-
"-packageDependencySCMToRegistryTransformation": {
|
|
174
|
-
status: "exposed",
|
|
175
|
-
via: "packages --scm-to-registry",
|
|
176
|
-
},
|
|
177
|
-
"-packageFingerprintPolicy": {
|
|
178
|
-
status: "exposed",
|
|
179
|
-
via: "packages --fingerprint-policy",
|
|
180
|
-
},
|
|
181
|
-
"-packageSigningEntityPolicy": {
|
|
182
|
-
status: "exposed",
|
|
183
|
-
via: "packages --signing-entity-policy",
|
|
184
|
-
},
|
|
185
|
-
"-parallel-testing-enabled": {
|
|
186
|
-
status: "exposed",
|
|
187
|
-
via: "test --parallel / --no-parallel",
|
|
188
|
-
},
|
|
189
|
-
"-parallel-testing-worker-count": {
|
|
190
|
-
status: "exposed",
|
|
191
|
-
via: "test --max-workers",
|
|
192
|
-
},
|
|
193
|
-
"-parallelizeTargets": {
|
|
194
|
-
status: "exposed",
|
|
195
|
-
via: "build --parallelize-targets",
|
|
196
|
-
},
|
|
197
|
-
"-platform": {
|
|
198
|
-
status: "exposed",
|
|
199
|
-
via: "platforms device-support --platform",
|
|
200
|
-
},
|
|
201
|
-
"-prepareDeviceSupport": {
|
|
202
|
-
status: "exposed",
|
|
203
|
-
via: "platforms device-support",
|
|
204
|
-
},
|
|
205
|
-
"-resolvePackageDependencies": {
|
|
206
|
-
status: "exposed",
|
|
207
|
-
via: "packages --resolve",
|
|
208
|
-
},
|
|
209
|
-
"-retry-tests-on-failure": { status: "exposed", via: "test --retry" },
|
|
210
|
-
"-run-tests-until-failure": {
|
|
211
|
-
status: "exposed",
|
|
212
|
-
via: "test --until-failure",
|
|
213
|
-
},
|
|
214
|
-
"-runFirstLaunch": { status: "exposed", via: "platforms first-launch" },
|
|
215
|
-
"-scheme": { status: "exposed", via: "build --scheme" },
|
|
216
|
-
"-scmProvider": { status: "exposed", via: "packages --scm-provider" },
|
|
217
|
-
"-sdk": { status: "exposed", via: "build --sdk" },
|
|
218
|
-
"-showBuildSettings": { status: "exposed", via: "settings" },
|
|
219
|
-
"-showBuildSettingsForIndex": {
|
|
220
|
-
status: "exposed",
|
|
221
|
-
via: "settings --for-index",
|
|
222
|
-
},
|
|
223
|
-
"-showBuildTimingSummary": { status: "exposed", via: "build --timing" },
|
|
224
|
-
"-showComponent": { status: "exposed", via: "platforms component show" },
|
|
225
|
-
"-showdestinations": { status: "exposed", via: "destinations" },
|
|
226
|
-
"-showsdks": { status: "exposed", via: "info --sdks" },
|
|
227
|
-
"-showTestPlans": { status: "exposed", via: "testplans" },
|
|
228
|
-
"-skip-test-configuration": {
|
|
229
|
-
status: "exposed",
|
|
230
|
-
via: "test --skip-configuration",
|
|
231
|
-
},
|
|
232
|
-
"-skip-testing": { status: "exposed", via: "test --skip" },
|
|
233
|
-
"-skipPackagePluginValidation": {
|
|
234
|
-
status: "exposed",
|
|
235
|
-
via: "build --skip-plugin-validation",
|
|
236
|
-
},
|
|
237
|
-
"-skipPackageSignatureValidation": {
|
|
238
|
-
status: "exposed",
|
|
239
|
-
via: "build --skip-signature-validation",
|
|
240
|
-
},
|
|
241
|
-
"-skipPackageUpdates": {
|
|
242
|
-
status: "exposed",
|
|
243
|
-
via: "build --skip-package-updates",
|
|
244
|
-
},
|
|
245
|
-
"-skipUnavailableActions": {
|
|
246
|
-
status: "exposed",
|
|
247
|
-
via: "build --skip-unavailable-actions",
|
|
248
|
-
},
|
|
249
|
-
"-target": { status: "exposed", via: "build --target" },
|
|
250
|
-
"-test-iterations": { status: "exposed", via: "test --iterations" },
|
|
251
|
-
"-test-repetition-relaunch-enabled": {
|
|
35
|
+
/**
|
|
36
|
+
* The commands an option can apply to, by kind.
|
|
37
|
+
*
|
|
38
|
+
* xcodebuild's own usage lines are the authority: `-target` and `-alltargets`
|
|
39
|
+
* sit on the same line as `-showBuildSettings`, so `settings` is expected to
|
|
40
|
+
* take them; `-showdestinations` appears only on the `-scheme` lines, so
|
|
41
|
+
* `destinations` is not expected to take a target.
|
|
42
|
+
*/
|
|
43
|
+
export const BUILD_FAMILY = [
|
|
44
|
+
"build",
|
|
45
|
+
"test",
|
|
46
|
+
"tests",
|
|
47
|
+
"analyze",
|
|
48
|
+
"archive",
|
|
49
|
+
];
|
|
50
|
+
export const SURFACES = {
|
|
51
|
+
/** Shapes compilation, so only the commands that compile something. */
|
|
52
|
+
build: BUILD_FAMILY,
|
|
53
|
+
/** Applies to any action word, `clean` included. */
|
|
54
|
+
action: [...BUILD_FAMILY, "clean"],
|
|
55
|
+
/** Changes what the project resolves to, which `settings` reports on. */
|
|
56
|
+
resolution: [...BUILD_FAMILY, "clean", "settings"],
|
|
57
|
+
/** Package resolution, which `packages` drives on its own. */
|
|
58
|
+
package: [...BUILD_FAMILY, "packages"],
|
|
59
|
+
/** Selects a scheme to act on. */
|
|
60
|
+
scheme: [
|
|
61
|
+
...BUILD_FAMILY,
|
|
62
|
+
"clean",
|
|
63
|
+
"settings",
|
|
64
|
+
"destinations",
|
|
65
|
+
"testplans",
|
|
66
|
+
"packages",
|
|
67
|
+
"localize",
|
|
68
|
+
],
|
|
69
|
+
/** Constrains which tests are run, and so which tests are enumerated. */
|
|
70
|
+
testing: ["test", "tests"],
|
|
71
|
+
};
|
|
72
|
+
/** `"settings --for-index"` -> `{ command: "settings", via: "settings --for-index" }`. */
|
|
73
|
+
export function at(via) {
|
|
74
|
+
return { command: via.split(/\s+/)[0], via };
|
|
75
|
+
}
|
|
76
|
+
/** The same flag on several commands, which is the common case. */
|
|
77
|
+
function sameFlag(commands, flag) {
|
|
78
|
+
return commands.map((command) => at(`${command} ${flag}`));
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* An option every command in a surface reaches by the same flag name, minus
|
|
82
|
+
* whichever of them is listed as a gap.
|
|
83
|
+
*/
|
|
84
|
+
function everywhere(surface, flag, options = {}) {
|
|
85
|
+
const absent = new Set([
|
|
86
|
+
...(options.missing ?? []).map((gap) => gap.command),
|
|
87
|
+
...(options.declined ?? []).map((gap) => gap.command),
|
|
88
|
+
]);
|
|
89
|
+
return {
|
|
252
90
|
status: "exposed",
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
91
|
+
surface,
|
|
92
|
+
on: [
|
|
93
|
+
...sameFlag(SURFACES[surface].filter((command) => !absent.has(command)), flag),
|
|
94
|
+
...(options.also ?? []).map(at),
|
|
95
|
+
],
|
|
96
|
+
...(options.missing ? { missing: options.missing } : {}),
|
|
97
|
+
...(options.declined ? { declined: options.declined } : {}),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/** An option reached from one place, which needs no surface. */
|
|
101
|
+
function only(...via) {
|
|
102
|
+
return { status: "exposed", on: via.map(at) };
|
|
103
|
+
}
|
|
104
|
+
const gap = (command, why) => ({ command, why });
|
|
105
|
+
/** The gaps this file exists to make visible, phrased once and shared. */
|
|
106
|
+
const NO_TARGET_MODE = "resolves a scheme only, so target-mode projects cannot be asked";
|
|
107
|
+
const CLEAN_IS_MINIMAL = "`clean` takes three flags today and xcodebuild accepts this one on a clean action";
|
|
108
|
+
export const OPTION_COVERAGE = {
|
|
109
|
+
"-allowProvisioningDeviceRegistration": only("archive --allow-device-registration", "export --allow-device-registration"),
|
|
110
|
+
"-allowProvisioningUpdates": everywhere("build", "--allow-provisioning", {
|
|
111
|
+
also: ["export --allow-provisioning"],
|
|
112
|
+
}),
|
|
113
|
+
"-alltargets": everywhere("resolution", "--all-targets", {
|
|
114
|
+
missing: [gap("settings", NO_TARGET_MODE), gap("clean", CLEAN_IS_MINIMAL)],
|
|
115
|
+
}),
|
|
116
|
+
"-arch": everywhere("resolution", "--arch", {
|
|
117
|
+
missing: [
|
|
118
|
+
gap("settings", "architecture-dependent settings cannot be asked for one arch"),
|
|
119
|
+
gap("clean", CLEAN_IS_MINIMAL),
|
|
120
|
+
],
|
|
121
|
+
}),
|
|
122
|
+
"-architecture": only("platforms device-support --architecture"),
|
|
123
|
+
"-archivePath": only("archive --archive-path", "export <path.xcarchive>"),
|
|
124
|
+
"-authenticationKeyID": only("archive --auth-key-id", "export --auth-key-id"),
|
|
125
|
+
"-authenticationKeyIssuerID": only("archive --auth-key-issuer", "export --auth-key-issuer"),
|
|
126
|
+
"-authenticationKeyPath": only("archive --auth-key-path", "export --auth-key-path"),
|
|
127
|
+
"-checkFirstLaunchStatus": only("platforms first-launch --status"),
|
|
128
|
+
"-clonedSourcePackagesDirPath": everywhere("package", "--cache"),
|
|
129
|
+
"-codesizeProfileOutputDir": everywhere("build", "--codesize"),
|
|
130
|
+
"-collect-test-diagnostics": only("test --diagnostics"),
|
|
131
|
+
"-configuration": everywhere("resolution", "--configuration"),
|
|
132
|
+
"-create-xcframework": only("xcframework"),
|
|
133
|
+
"-default-test-execution-time-allowance": only("test --default-test-timeout"),
|
|
134
|
+
"-defaultLanguage": only("localize export --default-language"),
|
|
135
|
+
"-defaultPackageRegistryURL": everywhere("package", "--registry-url"),
|
|
136
|
+
"-deleteComponent": only("platforms component delete"),
|
|
137
|
+
"-derivedDataPath": everywhere("resolution", "--derived-data", {
|
|
138
|
+
missing: [
|
|
139
|
+
gap("settings", "BUILT_PRODUCTS_DIR cannot be asked for the derived data a CI job uses"),
|
|
140
|
+
gap("packages", "resolved packages land in derived data, which cannot be redirected"),
|
|
141
|
+
],
|
|
142
|
+
}),
|
|
143
|
+
"-destination": everywhere("resolution", "--destination", {
|
|
144
|
+
missing: [gap("clean", CLEAN_IS_MINIMAL)],
|
|
145
|
+
}),
|
|
146
|
+
"-destination-timeout": everywhere("resolution", "--destination-timeout", {
|
|
147
|
+
missing: [
|
|
148
|
+
gap("settings", "resolves a device by name with no say over the wait"),
|
|
149
|
+
gap("clean", CLEAN_IS_MINIMAL),
|
|
150
|
+
],
|
|
151
|
+
}),
|
|
152
|
+
"-disableAutomaticPackageResolution": everywhere("package", "--no-auto-resolve"),
|
|
153
|
+
"-disablePackageRepositoryCache": everywhere("package", "--no-package-cache"),
|
|
154
|
+
"-downloadAllPlatforms": only("platforms download --all"),
|
|
155
|
+
"-downloadComponent": only("platforms component download"),
|
|
156
|
+
"-downloadPlatform": only("platforms download"),
|
|
157
|
+
"-enableAddressSanitizer": everywhere("build", "--sanitizer address"),
|
|
158
|
+
"-enableCodeCoverage": only("test --coverage"),
|
|
159
|
+
"-enableCodesizeProfile": everywhere("build", "--codesize"),
|
|
160
|
+
"-enablePerformanceTestsDiagnostics": only("test --perf-diagnostics"),
|
|
161
|
+
"-enableThreadSanitizer": everywhere("build", "--sanitizer thread"),
|
|
162
|
+
"-enableUndefinedBehaviorSanitizer": everywhere("build", "--sanitizer undefined"),
|
|
163
|
+
"-enumerate-tests": only("tests"),
|
|
164
|
+
"-exportArchive": only("export"),
|
|
165
|
+
"-exportLanguage": only("localize export --language"),
|
|
166
|
+
"-exportLocalizations": only("localize export"),
|
|
167
|
+
"-exportNotarizedApp": only("export --notarized"),
|
|
168
|
+
"-exportOptionsPlist": only("export --options"),
|
|
169
|
+
"-exportPath": only("export --output", "platforms download --export-path", "platforms component download --export-path"),
|
|
170
|
+
"-find-executable": only("find"),
|
|
171
|
+
"-find-library": only("find --library"),
|
|
172
|
+
"-hideShellScriptEnvironment": everywhere("build", "--hide-script-env"),
|
|
173
|
+
"-importComponent": only("platforms component import"),
|
|
174
|
+
"-importLocalizations": only("localize import"),
|
|
175
|
+
"-importPath": only("platforms component import --import-path"),
|
|
176
|
+
"-importPlatform": only("platforms import"),
|
|
177
|
+
"-jobs": everywhere("build", "--jobs"),
|
|
178
|
+
"-list": only("schemes"),
|
|
179
|
+
"-localizationPath": only("localize --path"),
|
|
180
|
+
"-maximum-concurrent-test-device-destinations": only("test --max-device-destinations"),
|
|
181
|
+
"-maximum-concurrent-test-simulator-destinations": only("test --max-sim-destinations"),
|
|
182
|
+
"-maximum-parallel-testing-workers": only("test --max-workers"),
|
|
183
|
+
"-maximum-test-execution-time-allowance": only("test --test-timeout"),
|
|
184
|
+
"-modelCode": only("platforms device-support --model-code"),
|
|
185
|
+
"-only-test-configuration": only("test --only-configuration"),
|
|
186
|
+
"-only-testing": everywhere("testing", "--only", {
|
|
187
|
+
missing: [
|
|
188
|
+
gap("tests", "enumeration cannot be constrained the way the run that follows it is"),
|
|
189
|
+
],
|
|
190
|
+
}),
|
|
191
|
+
"-onlyUsePackageVersionsFromResolvedFile": everywhere("package", "--offline"),
|
|
192
|
+
"-osVersion": only("platforms device-support --os-version"),
|
|
193
|
+
"-packageAuthorizationProvider": everywhere("package", "--package-auth"),
|
|
194
|
+
"-packageCachePath": everywhere("package", "--package-cache"),
|
|
195
|
+
"-packageDependencySCMToRegistryTransformation": everywhere("package", "--scm-to-registry"),
|
|
196
|
+
"-packageFingerprintPolicy": everywhere("package", "--fingerprint-policy"),
|
|
197
|
+
"-packageSigningEntityPolicy": everywhere("package", "--signing-entity-policy"),
|
|
198
|
+
"-parallel-testing-enabled": only("test --parallel / --no-parallel"),
|
|
199
|
+
"-parallel-testing-worker-count": only("test --max-workers"),
|
|
200
|
+
"-parallelizeTargets": everywhere("build", "--parallelize-targets"),
|
|
201
|
+
"-platform": only("platforms device-support --platform"),
|
|
202
|
+
"-prepareDeviceSupport": only("platforms device-support"),
|
|
203
|
+
"-resolvePackageDependencies": only("packages --resolve"),
|
|
204
|
+
"-retry-tests-on-failure": only("test --retry"),
|
|
205
|
+
"-run-tests-until-failure": only("test --until-failure"),
|
|
206
|
+
"-runFirstLaunch": only("platforms first-launch"),
|
|
207
|
+
"-scheme": everywhere("scheme", "--scheme"),
|
|
208
|
+
"-scmProvider": everywhere("package", "--scm-provider"),
|
|
209
|
+
"-sdk": everywhere("resolution", "--sdk", {
|
|
210
|
+
also: ["find --sdk"],
|
|
211
|
+
missing: [gap("clean", CLEAN_IS_MINIMAL)],
|
|
212
|
+
}),
|
|
213
|
+
"-showBuildSettings": only("settings"),
|
|
214
|
+
"-showBuildSettingsForIndex": only("settings --for-index"),
|
|
215
|
+
"-showBuildTimingSummary": everywhere("build", "--timing"),
|
|
216
|
+
"-showComponent": only("platforms component show"),
|
|
217
|
+
"-showdestinations": only("destinations"),
|
|
218
|
+
"-showsdks": only("info --sdks"),
|
|
219
|
+
"-showTestPlans": only("testplans"),
|
|
220
|
+
"-skip-test-configuration": only("test --skip-configuration"),
|
|
221
|
+
"-skip-testing": everywhere("testing", "--skip", {
|
|
222
|
+
missing: [
|
|
223
|
+
gap("tests", "enumeration cannot be constrained the way the run that follows it is"),
|
|
224
|
+
],
|
|
225
|
+
}),
|
|
226
|
+
"-skipPackagePluginValidation": everywhere("package", "--skip-plugin-validation"),
|
|
227
|
+
"-skipPackageSignatureValidation": everywhere("package", "--skip-signature-validation"),
|
|
228
|
+
"-skipPackageUpdates": everywhere("package", "--skip-package-updates"),
|
|
229
|
+
"-skipUnavailableActions": everywhere("build", "--skip-unavailable-actions"),
|
|
230
|
+
"-target": everywhere("resolution", "--target", {
|
|
231
|
+
missing: [gap("settings", NO_TARGET_MODE), gap("clean", CLEAN_IS_MINIMAL)],
|
|
232
|
+
}),
|
|
233
|
+
"-test-iterations": only("test --iterations"),
|
|
234
|
+
"-test-repetition-relaunch-enabled": only("test --relaunch"),
|
|
235
|
+
"-test-timeouts-enabled": only("test --test-timeout"),
|
|
236
|
+
"-testLanguage": only("test --language"),
|
|
237
|
+
"-testPlan": everywhere("testing", "--test-plan"),
|
|
238
|
+
"-testProductsPath": only("test --test-products"),
|
|
239
|
+
"-testRegion": only("test --region"),
|
|
240
|
+
"-toolchain": everywhere("resolution", "--toolchain", {
|
|
241
|
+
also: ["find --toolchain"],
|
|
242
|
+
missing: [
|
|
243
|
+
gap("settings", "settings cannot be resolved against a toolchain"),
|
|
244
|
+
gap("clean", CLEAN_IS_MINIMAL),
|
|
245
|
+
],
|
|
246
|
+
}),
|
|
247
|
+
"-version": only("info"),
|
|
248
|
+
"-xcconfig": everywhere("resolution", "--xcconfig", {
|
|
249
|
+
missing: [
|
|
250
|
+
gap("settings", "the overrides an xcconfig applies cannot be resolved before a build"),
|
|
251
|
+
gap("clean", CLEAN_IS_MINIMAL),
|
|
252
|
+
],
|
|
253
|
+
}),
|
|
254
|
+
"-xctestrun": only("test --xctestrun"),
|
|
264
255
|
"-json": {
|
|
265
256
|
status: "always",
|
|
266
257
|
why: "every read-only query asks for JSON, then reports TOON",
|
|
@@ -269,10 +260,11 @@ export const OPTION_COVERAGE = {
|
|
|
269
260
|
status: "always",
|
|
270
261
|
why: "set from the .xcodeproj found in the working directory",
|
|
271
262
|
},
|
|
272
|
-
"-resultBundlePath": {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
263
|
+
"-resultBundlePath": everywhere("action", "--artifacts-dir", {
|
|
264
|
+
missing: [
|
|
265
|
+
gap("clean", "writes a result bundle the caller cannot redirect"),
|
|
266
|
+
],
|
|
267
|
+
}),
|
|
276
268
|
"-skipMacroValidation": {
|
|
277
269
|
status: "always",
|
|
278
270
|
why: "macro trust is an interactive prompt in disguise, and an agent cannot answer it",
|
|
@@ -293,46 +285,439 @@ export const OPTION_COVERAGE = {
|
|
|
293
285
|
status: "always",
|
|
294
286
|
why: "set from the .xcworkspace found in the working directory",
|
|
295
287
|
},
|
|
296
|
-
"-convert-project":
|
|
288
|
+
"-convert-project": only("migrate --format"),
|
|
297
289
|
"-help": {
|
|
298
290
|
status: "superseded",
|
|
299
291
|
why: "`xcodebuild-axi --help`, which answers it in a fraction of the tokens",
|
|
300
292
|
},
|
|
301
|
-
"-license":
|
|
302
|
-
"-quiet":
|
|
303
|
-
|
|
304
|
-
|
|
293
|
+
"-license": only("platforms license"),
|
|
294
|
+
"-quiet": everywhere("action", "--log-level quiet", {
|
|
295
|
+
missing: [gap("clean", "the clean log cannot be quieted")],
|
|
296
|
+
}),
|
|
297
|
+
"-resultBundleVersion": everywhere("build", "--bundle-version"),
|
|
298
|
+
"-resultStreamPath": everywhere("build", "--stream"),
|
|
305
299
|
"-usage": {
|
|
306
300
|
status: "superseded",
|
|
307
301
|
why: "`xcodebuild-axi <command> --help`, per command rather than all 117 at once",
|
|
308
302
|
},
|
|
309
|
-
"-verbose":
|
|
303
|
+
"-verbose": everywhere("action", "--log-level verbose", {
|
|
304
|
+
missing: [gap("clean", "the clean log cannot be made verbose")],
|
|
305
|
+
}),
|
|
310
306
|
};
|
|
311
307
|
/** The build actions, classified the same way. */
|
|
312
308
|
export const ACTION_COVERAGE = {
|
|
313
|
-
build:
|
|
314
|
-
"build-for-testing":
|
|
315
|
-
analyze:
|
|
316
|
-
archive:
|
|
317
|
-
test:
|
|
318
|
-
"test-without-building":
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
docbuild: { status: "exposed", via: "build --docs" },
|
|
323
|
-
clean: { status: "exposed", via: "clean" },
|
|
324
|
-
install: { status: "exposed", via: "build --install" },
|
|
309
|
+
build: only("build"),
|
|
310
|
+
"build-for-testing": only("build --for-testing"),
|
|
311
|
+
analyze: only("analyze"),
|
|
312
|
+
archive: only("archive"),
|
|
313
|
+
test: only("test"),
|
|
314
|
+
"test-without-building": only("test --without-building"),
|
|
315
|
+
docbuild: only("build --docs"),
|
|
316
|
+
clean: only("clean"),
|
|
317
|
+
install: only("build --install"),
|
|
325
318
|
installsrc: {
|
|
326
319
|
status: "n/a",
|
|
327
320
|
why: "copies sources into SRCROOT as root; a packaging step, not an agent loop",
|
|
328
321
|
},
|
|
329
322
|
};
|
|
323
|
+
/**
|
|
324
|
+
* The second forms of an option, which `-help` documents only inside a usage
|
|
325
|
+
* line or a sentence. Nothing enumerates these, so they are the easiest kind
|
|
326
|
+
* of gap to ship: `-runFirstLaunch -checkForNewerComponents` is a flag on a
|
|
327
|
+
* flag, mentioned once, in prose.
|
|
328
|
+
*/
|
|
329
|
+
export const FORM_COVERAGE = {
|
|
330
|
+
"-version -sdk <name> <infoitem>": {
|
|
331
|
+
status: "missing",
|
|
332
|
+
from: "info",
|
|
333
|
+
why: "`info --sdks` lists canonical names; an SDK's Path or ProductBuildVersion cannot be asked for",
|
|
334
|
+
},
|
|
335
|
+
"-runFirstLaunch -checkForNewerComponents": only("platforms first-launch --check-updates"),
|
|
336
|
+
"-license check": only("platforms license"),
|
|
337
|
+
"-only-testing @<response-file>": only("test --only"),
|
|
338
|
+
"-skip-testing @<response-file>": only("test --skip"),
|
|
339
|
+
"-showBuildSettings -json": {
|
|
340
|
+
status: "always",
|
|
341
|
+
why: "always asked for as JSON, then reported as TOON",
|
|
342
|
+
},
|
|
343
|
+
"-create-xcframework -help": {
|
|
344
|
+
status: "superseded",
|
|
345
|
+
why: "`xcodebuild-axi xcframework --help`",
|
|
346
|
+
},
|
|
347
|
+
};
|
|
348
|
+
/**
|
|
349
|
+
* `-exportOptionsPlist` keys.
|
|
350
|
+
*
|
|
351
|
+
* The plist is the whole configuration surface of `-exportArchive`, and
|
|
352
|
+
* authoring one by hand is exactly the side quest `--method` exists to remove
|
|
353
|
+
* — so a key with no flag is a key that sends the agent back to writing XML.
|
|
354
|
+
*/
|
|
355
|
+
export const EXPORT_OPTION_COVERAGE = {
|
|
356
|
+
method: only("export --method"),
|
|
357
|
+
destination: only("export --upload"),
|
|
358
|
+
teamID: only("export --team"),
|
|
359
|
+
signingStyle: only("export --signing-style"),
|
|
360
|
+
uploadSymbols: only("export --no-upload-symbols"),
|
|
361
|
+
manageAppVersionAndBuildNumber: only("export --no-manage-version"),
|
|
362
|
+
provisioningProfiles: {
|
|
363
|
+
status: "missing",
|
|
364
|
+
from: "export",
|
|
365
|
+
why: "manual signing can be asked for but not completed — the profile per executable has no flag",
|
|
366
|
+
},
|
|
367
|
+
signingCertificate: {
|
|
368
|
+
status: "missing",
|
|
369
|
+
from: "export",
|
|
370
|
+
why: "manual signing cannot name the certificate to sign with",
|
|
371
|
+
},
|
|
372
|
+
installerSigningCertificate: {
|
|
373
|
+
status: "missing",
|
|
374
|
+
from: "export",
|
|
375
|
+
why: "a macOS installer package cannot name its signing certificate",
|
|
376
|
+
},
|
|
377
|
+
thinning: {
|
|
378
|
+
status: "missing",
|
|
379
|
+
from: "export",
|
|
380
|
+
why: "non-App Store exports cannot be thinned for a device variant",
|
|
381
|
+
},
|
|
382
|
+
stripSwiftSymbols: {
|
|
383
|
+
status: "missing",
|
|
384
|
+
from: "export",
|
|
385
|
+
why: "Swift symbols are always stripped, with no way to keep them",
|
|
386
|
+
},
|
|
387
|
+
testFlightInternalTestingOnly: {
|
|
388
|
+
status: "missing",
|
|
389
|
+
from: "export",
|
|
390
|
+
why: "a build cannot be marked internal-only, which is what a PR build wants",
|
|
391
|
+
},
|
|
392
|
+
distributionBundleIdentifier: {
|
|
393
|
+
status: "missing",
|
|
394
|
+
from: "export",
|
|
395
|
+
why: "an archive with several apps cannot pick which one to export",
|
|
396
|
+
},
|
|
397
|
+
generateAppStoreInformation: {
|
|
398
|
+
status: "missing",
|
|
399
|
+
from: "export",
|
|
400
|
+
why: "App Store information cannot be generated for an upload",
|
|
401
|
+
},
|
|
402
|
+
iCloudContainerEnvironment: {
|
|
403
|
+
status: "missing",
|
|
404
|
+
from: "export",
|
|
405
|
+
why: "a CloudKit app cannot choose the Development or Production container",
|
|
406
|
+
},
|
|
407
|
+
manifest: {
|
|
408
|
+
status: "missing",
|
|
409
|
+
from: "export",
|
|
410
|
+
why: "an over-the-web distribution manifest cannot be written",
|
|
411
|
+
},
|
|
412
|
+
embedOnDemandResourcesAssetPacksInBundle: {
|
|
413
|
+
status: "missing",
|
|
414
|
+
from: "export",
|
|
415
|
+
why: "on-demand resource asset packs cannot be embedded for testing",
|
|
416
|
+
},
|
|
417
|
+
onDemandResourcesAssetPacksBaseURL: {
|
|
418
|
+
status: "missing",
|
|
419
|
+
from: "export",
|
|
420
|
+
why: "on-demand resource asset packs cannot be pointed at a host",
|
|
421
|
+
},
|
|
422
|
+
};
|
|
423
|
+
/** `-create-xcframework`'s own options, which only its `-help` prints. */
|
|
424
|
+
export const XCFRAMEWORK_COVERAGE = {
|
|
425
|
+
"-framework": only("xcframework --framework"),
|
|
426
|
+
"-library": only("xcframework --library"),
|
|
427
|
+
"-headers": only("xcframework --headers"),
|
|
428
|
+
"-output": only("xcframework --output"),
|
|
429
|
+
"-archive": only("xcframework --archive"),
|
|
430
|
+
"-debug-symbols": only("xcframework --debug-symbols"),
|
|
431
|
+
"-allow-internal-distribution": only("xcframework --allow-internal-distribution"),
|
|
432
|
+
"-help": {
|
|
433
|
+
status: "superseded",
|
|
434
|
+
why: "`xcodebuild-axi xcframework --help`",
|
|
435
|
+
},
|
|
436
|
+
};
|
|
437
|
+
/**
|
|
438
|
+
* `xcresulttool`, which owns every answer about a run that already happened.
|
|
439
|
+
*
|
|
440
|
+
* The result bundle is this tool's source of truth (see AGENTS.md), so a leaf
|
|
441
|
+
* missing here is an answer the bundle holds and the tool cannot read out —
|
|
442
|
+
* `test --diagnostics` collecting a report nothing can open, for instance.
|
|
443
|
+
*/
|
|
444
|
+
export const XCRESULT_COVERAGE = {
|
|
445
|
+
"get build-results": only("result", "build", "test"),
|
|
446
|
+
"get test-results summary": only("result", "test"),
|
|
447
|
+
"get test-results tests": {
|
|
448
|
+
status: "missing",
|
|
449
|
+
from: "result",
|
|
450
|
+
why: "the full test tree of a finished run cannot be listed",
|
|
451
|
+
},
|
|
452
|
+
"get test-results test-details": {
|
|
453
|
+
status: "missing",
|
|
454
|
+
from: "result",
|
|
455
|
+
why: "the only source of a per-failure file and line; without it a failing test reports a message and no location",
|
|
456
|
+
},
|
|
457
|
+
"get test-results activities": {
|
|
458
|
+
status: "missing",
|
|
459
|
+
from: "result",
|
|
460
|
+
why: "the step-by-step activity trail of a failing test cannot be read",
|
|
461
|
+
},
|
|
462
|
+
"get test-results insights": {
|
|
463
|
+
status: "missing",
|
|
464
|
+
from: "result",
|
|
465
|
+
why: "Xcode's own diagnosis of a run is left on the floor",
|
|
466
|
+
},
|
|
467
|
+
"get test-results metrics": {
|
|
468
|
+
status: "missing",
|
|
469
|
+
from: "result",
|
|
470
|
+
why: "`test --perf-diagnostics` collects performance metrics nothing can read back",
|
|
471
|
+
},
|
|
472
|
+
"get log": {
|
|
473
|
+
status: "missing",
|
|
474
|
+
from: "result",
|
|
475
|
+
why: "the build log inside the bundle is reachable only as the raw transcript file",
|
|
476
|
+
},
|
|
477
|
+
"get content-availability": {
|
|
478
|
+
status: "missing",
|
|
479
|
+
from: "result",
|
|
480
|
+
why: "whether a bundle even has coverage or test results is found out by failing to read it",
|
|
481
|
+
},
|
|
482
|
+
"export diagnostics": {
|
|
483
|
+
status: "missing",
|
|
484
|
+
from: "result",
|
|
485
|
+
why: "`test --diagnostics` collects a diagnostics report that cannot be extracted",
|
|
486
|
+
},
|
|
487
|
+
"export attachments": {
|
|
488
|
+
status: "missing",
|
|
489
|
+
from: "result",
|
|
490
|
+
why: "UI test screenshots and attachments cannot be got out of the bundle",
|
|
491
|
+
},
|
|
492
|
+
"export metrics": {
|
|
493
|
+
status: "missing",
|
|
494
|
+
from: "result",
|
|
495
|
+
why: "performance measurements cannot be exported as CSV",
|
|
496
|
+
},
|
|
497
|
+
"export evaluations": {
|
|
498
|
+
status: "missing",
|
|
499
|
+
from: "result",
|
|
500
|
+
why: "evaluation attachments cannot be exported",
|
|
501
|
+
},
|
|
502
|
+
compare: {
|
|
503
|
+
status: "missing",
|
|
504
|
+
from: "result",
|
|
505
|
+
why: "two runs cannot be diffed, which is the question CI asks most",
|
|
506
|
+
},
|
|
507
|
+
merge: {
|
|
508
|
+
status: "missing",
|
|
509
|
+
from: "result",
|
|
510
|
+
why: "the bundles of a sharded test run cannot be combined",
|
|
511
|
+
},
|
|
512
|
+
metadata: {
|
|
513
|
+
status: "missing",
|
|
514
|
+
from: "result",
|
|
515
|
+
why: "a bundle's own metadata cannot be read",
|
|
516
|
+
},
|
|
517
|
+
"export coverage": {
|
|
518
|
+
status: "superseded",
|
|
519
|
+
why: "`coverage` reads the report with xccov rather than exporting an archive",
|
|
520
|
+
},
|
|
521
|
+
"get object": {
|
|
522
|
+
status: "n/a",
|
|
523
|
+
why: "deprecated by Xcode in favour of the typed subcommands",
|
|
524
|
+
},
|
|
525
|
+
"export object": {
|
|
526
|
+
status: "n/a",
|
|
527
|
+
why: "deprecated by Xcode in favour of get attachments|diagnostics|coverage",
|
|
528
|
+
},
|
|
529
|
+
graph: { status: "n/a", why: "deprecated by Xcode" },
|
|
530
|
+
formatDescription: { status: "n/a", why: "deprecated by Xcode" },
|
|
531
|
+
};
|
|
532
|
+
/** `xccov`, which owns coverage. */
|
|
533
|
+
export const XCCOV_COVERAGE = {
|
|
534
|
+
"view --report": only("coverage"),
|
|
535
|
+
"view --report --only-targets": only("coverage"),
|
|
536
|
+
"view --report --files-for-target": only("coverage --target"),
|
|
537
|
+
"view --report --file-list": only("coverage --files"),
|
|
538
|
+
"view --report --functions-for-file": {
|
|
539
|
+
status: "missing",
|
|
540
|
+
from: "coverage",
|
|
541
|
+
why: "coverage stops at the file, so the uncovered function has no name",
|
|
542
|
+
},
|
|
543
|
+
"view --archive": {
|
|
544
|
+
status: "missing",
|
|
545
|
+
from: "coverage",
|
|
546
|
+
why: "a standalone .xccovarchive cannot be read, only a result bundle",
|
|
547
|
+
},
|
|
548
|
+
"view --file": {
|
|
549
|
+
status: "missing",
|
|
550
|
+
from: "coverage",
|
|
551
|
+
why: "the per-line coverage of one file cannot be printed",
|
|
552
|
+
},
|
|
553
|
+
diff: {
|
|
554
|
+
status: "missing",
|
|
555
|
+
from: "coverage",
|
|
556
|
+
why: "'did coverage drop' cannot be answered from two bundles this tool wrote",
|
|
557
|
+
},
|
|
558
|
+
merge: {
|
|
559
|
+
status: "missing",
|
|
560
|
+
from: "coverage",
|
|
561
|
+
why: "the coverage of a sharded run cannot be combined",
|
|
562
|
+
},
|
|
563
|
+
};
|
|
564
|
+
/**
|
|
565
|
+
* `simctl`, which owns simulators.
|
|
566
|
+
*
|
|
567
|
+
* `sim` exists to put a destination into the state a build or test run needs,
|
|
568
|
+
* and stops there. The rest is classified so the boundary is a decision on
|
|
569
|
+
* the record rather than an omission.
|
|
570
|
+
*/
|
|
571
|
+
export const SIMCTL_COVERAGE = {
|
|
572
|
+
list: only("sim list"),
|
|
573
|
+
boot: only("sim boot"),
|
|
574
|
+
shutdown: only("sim shutdown"),
|
|
575
|
+
erase: only("sim erase"),
|
|
576
|
+
install: {
|
|
577
|
+
status: "missing",
|
|
578
|
+
from: "sim",
|
|
579
|
+
why: "a built .app cannot be put on the simulator it was built for",
|
|
580
|
+
},
|
|
581
|
+
launch: {
|
|
582
|
+
status: "missing",
|
|
583
|
+
from: "sim",
|
|
584
|
+
why: "the app a build just produced cannot be run",
|
|
585
|
+
},
|
|
586
|
+
terminate: { status: "missing", why: "a running app cannot be stopped" },
|
|
587
|
+
uninstall: { status: "missing", why: "an installed app cannot be removed" },
|
|
588
|
+
listapps: {
|
|
589
|
+
status: "missing",
|
|
590
|
+
from: "sim",
|
|
591
|
+
why: "what is installed on a simulator cannot be listed",
|
|
592
|
+
},
|
|
593
|
+
create: { status: "missing", why: "a missing device cannot be created" },
|
|
594
|
+
delete: {
|
|
595
|
+
status: "missing",
|
|
596
|
+
from: "sim",
|
|
597
|
+
why: "stale devices cannot be reclaimed, and they cost gigabytes",
|
|
598
|
+
},
|
|
599
|
+
io: {
|
|
600
|
+
status: "missing",
|
|
601
|
+
from: "sim",
|
|
602
|
+
why: "a screenshot of a failing UI cannot be taken",
|
|
603
|
+
},
|
|
604
|
+
openurl: {
|
|
605
|
+
status: "missing",
|
|
606
|
+
from: "sim",
|
|
607
|
+
why: "a deep link cannot be opened, which is how deep links are tested",
|
|
608
|
+
},
|
|
609
|
+
privacy: {
|
|
610
|
+
status: "missing",
|
|
611
|
+
from: "sim",
|
|
612
|
+
why: "a permission prompt cannot be granted ahead of a UI test",
|
|
613
|
+
},
|
|
614
|
+
push: {
|
|
615
|
+
status: "missing",
|
|
616
|
+
from: "sim",
|
|
617
|
+
why: "a push notification cannot be simulated",
|
|
618
|
+
},
|
|
619
|
+
status_bar: {
|
|
620
|
+
status: "missing",
|
|
621
|
+
from: "sim",
|
|
622
|
+
why: "the status bar cannot be pinned, which screenshot tests need",
|
|
623
|
+
},
|
|
624
|
+
ui: {
|
|
625
|
+
status: "missing",
|
|
626
|
+
from: "sim",
|
|
627
|
+
why: "dark mode and content size cannot be set for a test run",
|
|
628
|
+
},
|
|
629
|
+
spawn: {
|
|
630
|
+
status: "n/a",
|
|
631
|
+
why: "running arbitrary processes on a device is not this tool's job",
|
|
632
|
+
},
|
|
633
|
+
diagnose: {
|
|
634
|
+
status: "n/a",
|
|
635
|
+
why: "a sysdiagnose is an Apple support artifact, not an agent loop",
|
|
636
|
+
},
|
|
637
|
+
addmedia: {
|
|
638
|
+
status: "n/a",
|
|
639
|
+
why: "photo library fixtures belong to a test target, not a build wrapper",
|
|
640
|
+
},
|
|
641
|
+
appinfo: {
|
|
642
|
+
status: "n/a",
|
|
643
|
+
why: "`listapps` answers the same question for an agent",
|
|
644
|
+
},
|
|
645
|
+
get_app_container: {
|
|
646
|
+
status: "n/a",
|
|
647
|
+
why: "a container path is a debugging detail, not a build output",
|
|
648
|
+
},
|
|
649
|
+
getenv: {
|
|
650
|
+
status: "n/a",
|
|
651
|
+
why: "device environment variables are a simctl debugging tool",
|
|
652
|
+
},
|
|
653
|
+
clone: {
|
|
654
|
+
status: "n/a",
|
|
655
|
+
why: "device farming is outside a build and test loop",
|
|
656
|
+
},
|
|
657
|
+
rename: { status: "n/a", why: "device naming is a Simulator.app concern" },
|
|
658
|
+
upgrade: {
|
|
659
|
+
status: "n/a",
|
|
660
|
+
why: "runtime migration is a Simulator.app concern",
|
|
661
|
+
},
|
|
662
|
+
reboot: { status: "n/a", why: "shutdown and boot cover what a run needs" },
|
|
663
|
+
runtime: {
|
|
664
|
+
status: "n/a",
|
|
665
|
+
why: "`platforms` downloads runtimes through xcodebuild",
|
|
666
|
+
},
|
|
667
|
+
location: {
|
|
668
|
+
status: "n/a",
|
|
669
|
+
why: "simulated location belongs to a test target",
|
|
670
|
+
},
|
|
671
|
+
keychain: {
|
|
672
|
+
status: "n/a",
|
|
673
|
+
why: "seeding a keychain belongs to a test target",
|
|
674
|
+
},
|
|
675
|
+
logverbose: { status: "n/a", why: "a simctl debugging switch" },
|
|
676
|
+
icloud_sync: {
|
|
677
|
+
status: "n/a",
|
|
678
|
+
why: "an iCloud testing concern, not a build one",
|
|
679
|
+
},
|
|
680
|
+
install_app_data: {
|
|
681
|
+
status: "n/a",
|
|
682
|
+
why: "app data fixtures belong to a test target",
|
|
683
|
+
},
|
|
684
|
+
personalization: {
|
|
685
|
+
status: "n/a",
|
|
686
|
+
why: "personalization manifests are a device provisioning concern",
|
|
687
|
+
},
|
|
688
|
+
pair: { status: "n/a", why: "watch pairing is a Simulator.app concern" },
|
|
689
|
+
pair_activate: {
|
|
690
|
+
status: "n/a",
|
|
691
|
+
why: "watch pairing is a Simulator.app concern",
|
|
692
|
+
},
|
|
693
|
+
unpair: { status: "n/a", why: "watch pairing is a Simulator.app concern" },
|
|
694
|
+
pbcopy: {
|
|
695
|
+
status: "n/a",
|
|
696
|
+
why: "pasteboard plumbing belongs to a test target",
|
|
697
|
+
},
|
|
698
|
+
pbpaste: {
|
|
699
|
+
status: "n/a",
|
|
700
|
+
why: "pasteboard plumbing belongs to a test target",
|
|
701
|
+
},
|
|
702
|
+
pbsync: {
|
|
703
|
+
status: "n/a",
|
|
704
|
+
why: "pasteboard plumbing belongs to a test target",
|
|
705
|
+
},
|
|
706
|
+
help: { status: "superseded", why: "`xcodebuild-axi sim --help`" },
|
|
707
|
+
};
|
|
708
|
+
/** Every non-xcodebuild surface this tool wraps, for one combined number. */
|
|
709
|
+
export const COMPANION_SURFACES = {
|
|
710
|
+
xcresulttool: XCRESULT_COVERAGE,
|
|
711
|
+
xccov: XCCOV_COVERAGE,
|
|
712
|
+
simctl: SIMCTL_COVERAGE,
|
|
713
|
+
};
|
|
330
714
|
export function tally(map) {
|
|
331
715
|
const values = Object.values(map);
|
|
332
716
|
const count = (status) => values.filter((entry) => entry.status === status).length;
|
|
333
717
|
const exposed = count("exposed");
|
|
334
718
|
const always = count("always");
|
|
335
719
|
const superseded = count("superseded");
|
|
720
|
+
const missing = count("missing");
|
|
336
721
|
const na = count("n/a");
|
|
337
722
|
const covered = exposed + always + superseded;
|
|
338
723
|
return {
|
|
@@ -340,11 +725,73 @@ export function tally(map) {
|
|
|
340
725
|
exposed,
|
|
341
726
|
always,
|
|
342
727
|
superseded,
|
|
728
|
+
missing,
|
|
343
729
|
na,
|
|
344
730
|
covered,
|
|
345
731
|
// `n/a` options stay in the denominator on purpose. Declining to wrap
|
|
346
732
|
// something is a choice this number should have to pay for.
|
|
347
|
-
percent:
|
|
733
|
+
percent: percent(covered, values.length),
|
|
348
734
|
};
|
|
349
735
|
}
|
|
736
|
+
export function percent(part, whole) {
|
|
737
|
+
return whole === 0 ? 100 : Math.round((part / whole) * 1000) / 10;
|
|
738
|
+
}
|
|
739
|
+
/** Every command an option applies to, whether or not it reaches it. */
|
|
740
|
+
export function applicable(entry) {
|
|
741
|
+
if (entry.status !== "exposed")
|
|
742
|
+
return [];
|
|
743
|
+
const commands = new Set(entry.surface ? SURFACES[entry.surface] : []);
|
|
744
|
+
for (const exposure of entry.on)
|
|
745
|
+
commands.add(exposure.command);
|
|
746
|
+
for (const item of entry.declined ?? [])
|
|
747
|
+
commands.add(item.command);
|
|
748
|
+
for (const item of entry.missing ?? [])
|
|
749
|
+
commands.add(item.command);
|
|
750
|
+
return [...commands];
|
|
751
|
+
}
|
|
752
|
+
/**
|
|
753
|
+
* Coverage counted per command rather than per option.
|
|
754
|
+
*
|
|
755
|
+
* The headline number asks whether an option is reachable at all; this one
|
|
756
|
+
* asks whether it is reachable from where you are standing, which is the
|
|
757
|
+
* question an agent that just got `unknown flag --target` was asking.
|
|
758
|
+
*/
|
|
759
|
+
export function reach(map) {
|
|
760
|
+
let reached = 0;
|
|
761
|
+
let declined = 0;
|
|
762
|
+
let missing = 0;
|
|
763
|
+
for (const entry of Object.values(map)) {
|
|
764
|
+
if (entry.status !== "exposed")
|
|
765
|
+
continue;
|
|
766
|
+
reached += new Set(entry.on.map((exposure) => exposure.command)).size;
|
|
767
|
+
declined += entry.declined?.length ?? 0;
|
|
768
|
+
missing += entry.missing?.length ?? 0;
|
|
769
|
+
}
|
|
770
|
+
const pairs = reached + declined + missing;
|
|
771
|
+
return {
|
|
772
|
+
pairs,
|
|
773
|
+
reached,
|
|
774
|
+
declined,
|
|
775
|
+
missing,
|
|
776
|
+
percent: percent(reached, pairs),
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
/** Every gap in a map, as `option` -> the commands that should reach it. */
|
|
780
|
+
export function gaps(map) {
|
|
781
|
+
const out = [];
|
|
782
|
+
for (const [option, entry] of Object.entries(map)) {
|
|
783
|
+
if (entry.status !== "exposed")
|
|
784
|
+
continue;
|
|
785
|
+
for (const item of entry.missing ?? []) {
|
|
786
|
+
out.push({ option, command: item.command, why: item.why });
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
return out;
|
|
790
|
+
}
|
|
791
|
+
/** The README's one-line answer to "how do I reach this?". */
|
|
792
|
+
export function describe(entry) {
|
|
793
|
+
return entry.status === "exposed"
|
|
794
|
+
? entry.on.map((exposure) => exposure.via).join(", ")
|
|
795
|
+
: entry.why;
|
|
796
|
+
}
|
|
350
797
|
//# sourceMappingURL=surface.js.map
|