@expo/build-tools 22.3.0 → 22.5.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/dist/ios/xcode.d.ts +3 -0
- package/dist/ios/xcode.js +22 -0
- package/dist/steps/functions/downloadBuild.js +25 -1
- package/dist/steps/functions/installMaestro.js +92 -11
- package/dist/steps/functions/launchApplication.d.ts +3 -1
- package/dist/steps/functions/launchApplication.js +84 -5
- package/dist/steps/utils/appiumCommandSummary.d.ts +9 -0
- package/dist/steps/utils/appiumCommandSummary.js +397 -0
- package/dist/steps/utils/appiumCommands.generated.d.ts +4 -0
- package/dist/steps/utils/appiumCommands.generated.js +2 -0
- package/dist/steps/utils/appiumEvents.js +2 -1
- package/dist/steps/utils/argentArtifacts.d.ts +1 -0
- package/dist/steps/utils/argentArtifacts.js +13 -6
- package/dist/steps/utils/ios/xcactivitylog.js +2 -8
- package/dist/utils/IosSimulatorUtils.d.ts +8 -0
- package/dist/utils/IosSimulatorUtils.js +9 -0
- package/dist/utils/download.d.ts +4 -0
- package/dist/utils/download.js +10 -0
- package/package.json +4 -3
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getXcodeVersionAsync = getXcodeVersionAsync;
|
|
7
|
+
const eas_build_job_1 = require("@expo/eas-build-job");
|
|
8
|
+
const turtle_spawn_1 = __importDefault(require("@expo/turtle-spawn"));
|
|
9
|
+
async function getXcodeVersionAsync({ env }) {
|
|
10
|
+
let stdout;
|
|
11
|
+
try {
|
|
12
|
+
({ stdout } = await (0, turtle_spawn_1.default)('xcodebuild', ['-version'], { stdio: 'pipe', env }));
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
throw new eas_build_job_1.SystemError('Failed to get Xcode version', { cause: error });
|
|
16
|
+
}
|
|
17
|
+
const version = /^Xcode\s+(\d+(?:\.\d+)*)$/m.exec(stdout)?.[1];
|
|
18
|
+
if (!version) {
|
|
19
|
+
throw new eas_build_job_1.SystemError(`Failed to determine Xcode version from: ${stdout.trim()}`);
|
|
20
|
+
}
|
|
21
|
+
return version;
|
|
22
|
+
}
|
|
@@ -19,6 +19,8 @@ const node_path_1 = __importDefault(require("node:path"));
|
|
|
19
19
|
const stream_1 = __importDefault(require("stream"));
|
|
20
20
|
const util_1 = require("util");
|
|
21
21
|
const zod_1 = require("zod");
|
|
22
|
+
const bplist_parser_1 = __importDefault(require("bplist-parser"));
|
|
23
|
+
const plist_1 = __importDefault(require("plist"));
|
|
22
24
|
const artifacts_1 = require("../../utils/artifacts");
|
|
23
25
|
const files_1 = require("../../utils/files");
|
|
24
26
|
const retryOnDNSFailure_1 = require("../../utils/retryOnDNSFailure");
|
|
@@ -163,12 +165,34 @@ async function downloadBuildAsync(params) {
|
|
|
163
165
|
onlyFiles: false,
|
|
164
166
|
onlyDirectories: false,
|
|
165
167
|
});
|
|
168
|
+
let matchingFilesRoot = extractionDirectory;
|
|
169
|
+
if (matchingFiles.length === 0 &&
|
|
170
|
+
extensions.includes('app') &&
|
|
171
|
+
(await isIosAppBundleAsync(extractionDirectory))) {
|
|
172
|
+
const appBundlePath = `${extractionDirectory}.app`;
|
|
173
|
+
await node_fs_1.default.promises.rename(extractionDirectory, appBundlePath);
|
|
174
|
+
matchingFiles.push(appBundlePath);
|
|
175
|
+
matchingFilesRoot = node_path_1.default.dirname(appBundlePath);
|
|
176
|
+
}
|
|
166
177
|
if (matchingFiles.length === 0) {
|
|
167
178
|
throw new eas_build_job_1.UserError('EAS_DOWNLOAD_BUILD_NO_MATCHING_FILES', `No ${extensions.map(ext => `.${ext}`).join(', ')} entries found in the archive.`);
|
|
168
179
|
}
|
|
169
|
-
logger.info(`Found ${matchingFiles.length} matching ${(0, strings_1.pluralize)(matchingFiles.length, 'entry')}:\n${matchingFiles.map(f => `- ${node_path_1.default.relative(
|
|
180
|
+
logger.info(`Found ${matchingFiles.length} matching ${(0, strings_1.pluralize)(matchingFiles.length, 'entry')}:\n${matchingFiles.map(f => `- ${node_path_1.default.relative(matchingFilesRoot, f)}`).join('\n')}`);
|
|
170
181
|
return { artifactPath: matchingFiles[0] };
|
|
171
182
|
}
|
|
183
|
+
async function isIosAppBundleAsync(directory) {
|
|
184
|
+
try {
|
|
185
|
+
const infoPlist = await node_fs_1.default.promises.readFile(node_path_1.default.join(directory, 'Info.plist'));
|
|
186
|
+
const isBinaryPlist = infoPlist.subarray(0, 8).toString('ascii') === 'bplist00';
|
|
187
|
+
const parsedInfoPlist = (isBinaryPlist
|
|
188
|
+
? bplist_parser_1.default.parseBuffer(infoPlist)[0]
|
|
189
|
+
: plist_1.default.parse(infoPlist.toString('utf8')));
|
|
190
|
+
return parsedInfoPlist?.CFBundlePackageType === 'APPL';
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
172
196
|
function parseHttpApplicationArchiveUrl(value) {
|
|
173
197
|
try {
|
|
174
198
|
const applicationArchiveUrl = zod_1.z.string().parse(value);
|
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.createInstallMaestroBuildFunction = createInstallMaestroBuildFunction;
|
|
7
7
|
exports.installIdbFromBrew = installIdbFromBrew;
|
|
8
|
+
const downloader_1 = __importDefault(require("@expo/downloader"));
|
|
8
9
|
const eas_build_job_1 = require("@expo/eas-build-job");
|
|
9
10
|
const results_1 = require("@expo/results");
|
|
10
11
|
const steps_1 = require("@expo/steps");
|
|
@@ -16,6 +17,10 @@ const path_1 = __importDefault(require("path"));
|
|
|
16
17
|
const semver_1 = __importDefault(require("semver"));
|
|
17
18
|
const maestroBackend_1 = require("./maestroBackend");
|
|
18
19
|
const datadog_1 = require("../../datadog");
|
|
20
|
+
const xcode_1 = require("../../ios/xcode");
|
|
21
|
+
const IosSimulatorUtils_1 = require("../../utils/IosSimulatorUtils");
|
|
22
|
+
const download_1 = require("../../utils/download");
|
|
23
|
+
const MAESTRO_RUNNER_WDA_CACHE_DOWNLOAD_TIMEOUT_MS = 20_000;
|
|
19
24
|
function createInstallMaestroBuildFunction() {
|
|
20
25
|
return new steps_1.BuildFunction({
|
|
21
26
|
namespace: 'eas',
|
|
@@ -118,10 +123,12 @@ function createInstallMaestroBuildFunction() {
|
|
|
118
123
|
requestedVersion === 'latest' ||
|
|
119
124
|
(requestedVersion === undefined &&
|
|
120
125
|
(!currentMaestroRunnerVersion || semver_1.default.gt(currentMaestroRunnerVersion, '1.1.15'))))) {
|
|
121
|
-
|
|
126
|
+
// `getXcodeVersionAsync` returns the raw version (e.g. "16.4"), which
|
|
127
|
+
// `semver.coerce` normalizes (e.g. "16.4.0") for comparison and display.
|
|
128
|
+
const xcodeVersion = semver_1.default.coerce(await (0, xcode_1.getXcodeVersionAsync)({ env }));
|
|
122
129
|
// maestro-runner 1.1.16 added `arch` to its xcodebuild destination. Xcode versions
|
|
123
130
|
// below 26 reject that option, so use the last compatible maestro-runner version.
|
|
124
|
-
if (semver_1.default.lt(xcodeVersion, '26.0.0')) {
|
|
131
|
+
if (xcodeVersion && semver_1.default.lt(xcodeVersion, '26.0.0')) {
|
|
125
132
|
if (requestedMaestroRunnerVersion) {
|
|
126
133
|
throw new eas_build_job_1.UserError('ERR_MAESTRO_INVALID_INPUT', `maestro-runner ${requestedVersion} is not compatible with Xcode ${xcodeVersion}. Use maestro-runner 1.1.15 or an Xcode 26+ image.`);
|
|
127
134
|
}
|
|
@@ -147,6 +154,12 @@ function createInstallMaestroBuildFunction() {
|
|
|
147
154
|
logger.error(maestroVersionResult.reason, 'Failed to get Maestro version.');
|
|
148
155
|
throw new Error(`Failed to ensure ${backend} is installed.`);
|
|
149
156
|
}
|
|
157
|
+
if (backend === 'maestro-runner' && global.runtimePlatform === steps_1.BuildRuntimePlatform.DARWIN) {
|
|
158
|
+
await installMaestroRunnerWdaCache({
|
|
159
|
+
logger,
|
|
160
|
+
env,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
150
163
|
logger.info(`${backend} ${maestroVersionResult.value} is ready.`);
|
|
151
164
|
outputs.maestro_version.set(maestroVersionResult.value);
|
|
152
165
|
datadog_1.Datadog.distribution('eas.maestro.install', 1, {
|
|
@@ -156,19 +169,87 @@ function createInstallMaestroBuildFunction() {
|
|
|
156
169
|
},
|
|
157
170
|
});
|
|
158
171
|
}
|
|
159
|
-
async function
|
|
160
|
-
|
|
172
|
+
async function installMaestroRunnerWdaCache({ logger, env, }) {
|
|
173
|
+
if (!env.HOME) {
|
|
174
|
+
logger.warn('Skipping the prebuilt WebDriverAgent cache because the $HOME environment variable is empty.');
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
const maestroRunnerHome = path_1.default.join(env.HOME, '.maestro-runner');
|
|
161
178
|
try {
|
|
162
|
-
|
|
179
|
+
const wdaVersion = await getMaestroRunnerWdaVersion({ maestroRunnerHome });
|
|
180
|
+
if (!wdaVersion) {
|
|
181
|
+
logger.info('Skipping the prebuilt WebDriverAgent cache because the installed WDA version is unknown.');
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const xcodeVersion = await (0, xcode_1.getXcodeVersionAsync)({ env });
|
|
185
|
+
const iosRuntimes = await IosSimulatorUtils_1.IosSimulatorUtils.getAvailableRuntimesAsync({ env });
|
|
186
|
+
const iosRuntimeIdentifierPrefix = 'com.apple.CoreSimulator.SimRuntime.iOS-';
|
|
187
|
+
// maestro-runner derives its WDA cache key from the runtime identifier, not from the runtime
|
|
188
|
+
// version. These values can differ for patched runtimes, for example the iOS-26-3 identifier
|
|
189
|
+
// can report version 26.3.1.
|
|
190
|
+
const iosRuntimeVersions = [
|
|
191
|
+
...new Set(iosRuntimes.map(runtime => runtime.identifier.slice(iosRuntimeIdentifierPrefix.length).replaceAll('-', '.'))),
|
|
192
|
+
];
|
|
193
|
+
if (iosRuntimeVersions.length === 0) {
|
|
194
|
+
logger.info('Skipping the prebuilt WebDriverAgent cache because no iOS runtime is available.');
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
const tempDirectory = await fs_1.default.promises.mkdtemp(path_1.default.join(os_1.default.tmpdir(), 'install_maestro_runner_wda_cache'));
|
|
198
|
+
try {
|
|
199
|
+
const archivePath = path_1.default.join(tempDirectory, 'wda-cache.tar.gz');
|
|
200
|
+
const directArchiveUrl = `https://storage.googleapis.com/turtle-v2/maestro-runner-wda-cache/` +
|
|
201
|
+
`xcode-${encodeURIComponent(xcodeVersion)}-wda-${encodeURIComponent(wdaVersion)}.tar.gz`;
|
|
202
|
+
const proxiedArchiveUrl = (0, download_1.getProxiedDownloadUrl)({
|
|
203
|
+
directUrl: directArchiveUrl,
|
|
204
|
+
proxyBaseUrl: env.EAS_BUILD_COCOAPODS_CACHE_URL,
|
|
205
|
+
});
|
|
206
|
+
logger.info(`Downloading the prebuilt WebDriverAgent cache for Xcode ${xcodeVersion}`);
|
|
207
|
+
if (proxiedArchiveUrl) {
|
|
208
|
+
try {
|
|
209
|
+
await (0, downloader_1.default)(proxiedArchiveUrl, archivePath, {
|
|
210
|
+
retry: 3,
|
|
211
|
+
timeout: MAESTRO_RUNNER_WDA_CACHE_DOWNLOAD_TIMEOUT_MS,
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
catch (err) {
|
|
215
|
+
logger.debug({ err }, 'Failed to download the prebuilt WebDriverAgent cache via the proxy; falling back to the direct URL.');
|
|
216
|
+
await (0, downloader_1.default)(directArchiveUrl, archivePath, {
|
|
217
|
+
retry: 3,
|
|
218
|
+
timeout: MAESTRO_RUNNER_WDA_CACHE_DOWNLOAD_TIMEOUT_MS,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
await (0, downloader_1.default)(directArchiveUrl, archivePath, {
|
|
224
|
+
retry: 3,
|
|
225
|
+
timeout: MAESTRO_RUNNER_WDA_CACHE_DOWNLOAD_TIMEOUT_MS,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
await fs_1.default.promises.mkdir(maestroRunnerHome, { recursive: true });
|
|
229
|
+
await (0, turtle_spawn_1.default)('tar', ['-xzf', archivePath, '-C', maestroRunnerHome], { logger, env });
|
|
230
|
+
const genericProductsDirectory = path_1.default.join(maestroRunnerHome, 'cache', 'wda-builds', 'generic', 'DerivedData', 'Build', 'Products');
|
|
231
|
+
for (const runtimeVersion of iosRuntimeVersions) {
|
|
232
|
+
const productsDirectory = path_1.default.join(maestroRunnerHome, 'cache', 'wda-builds', `sim-ios${runtimeVersion}-iphone`, 'DerivedData', 'Build', 'Products');
|
|
233
|
+
await fs_1.default.promises.cp(genericProductsDirectory, productsDirectory, { recursive: true });
|
|
234
|
+
}
|
|
235
|
+
logger.info(`Installed the prebuilt WebDriverAgent cache for iOS ${iosRuntimeVersions.join(', ')}.`);
|
|
236
|
+
}
|
|
237
|
+
finally {
|
|
238
|
+
await fs_1.default.promises.rm(tempDirectory, { force: true, recursive: true });
|
|
239
|
+
}
|
|
163
240
|
}
|
|
164
|
-
catch (
|
|
165
|
-
|
|
241
|
+
catch (err) {
|
|
242
|
+
logger.warn({ err }, 'Failed to install the prebuilt WebDriverAgent cache. maestro-runner will build WebDriverAgent when it is needed.');
|
|
166
243
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
244
|
+
}
|
|
245
|
+
async function getMaestroRunnerWdaVersion({ maestroRunnerHome, }) {
|
|
246
|
+
try {
|
|
247
|
+
const packageJson = JSON.parse(await fs_1.default.promises.readFile(path_1.default.join(maestroRunnerHome, 'drivers', 'ios', 'WebDriverAgent', 'package.json'), 'utf8'));
|
|
248
|
+
return typeof packageJson.version === 'string' ? packageJson.version : null;
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
return null;
|
|
170
252
|
}
|
|
171
|
-
return xcodeVersion;
|
|
172
253
|
}
|
|
173
254
|
async function getMaestroVersion({ env, backend, }) {
|
|
174
255
|
switch (backend) {
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { bunyan } from '@expo/logger';
|
|
2
2
|
import { BuildFunction, BuildRuntimePlatform, BuildStepEnv } from '@expo/steps';
|
|
3
3
|
export declare function createLaunchApplicationFunction(): BuildFunction;
|
|
4
|
-
export declare function launchApplicationAsync({ applicationIdentifier, activityName, runtimePlatform, env, logger, }: {
|
|
4
|
+
export declare function launchApplicationAsync({ applicationIdentifier, activityName, launchArgs, openUrl, runtimePlatform, env, logger, }: {
|
|
5
5
|
applicationIdentifier: string;
|
|
6
6
|
activityName?: string;
|
|
7
|
+
launchArgs?: string[];
|
|
8
|
+
openUrl?: string;
|
|
7
9
|
runtimePlatform: BuildRuntimePlatform;
|
|
8
10
|
env: BuildStepEnv;
|
|
9
11
|
logger: bunyan;
|
|
@@ -8,6 +8,8 @@ exports.launchApplicationAsync = launchApplicationAsync;
|
|
|
8
8
|
const eas_build_job_1 = require("@expo/eas-build-job");
|
|
9
9
|
const steps_1 = require("@expo/steps");
|
|
10
10
|
const turtle_spawn_1 = __importDefault(require("@expo/turtle-spawn"));
|
|
11
|
+
const IOS_URL_SCHEME_APPROVAL_DOMAIN = 'com.apple.launchservices.schemeapproval';
|
|
12
|
+
const IOS_URL_SCHEME_APPROVAL_KEY_PREFIX = 'com.apple.CoreSimulator.CoreSimulatorBridge-->';
|
|
11
13
|
function createLaunchApplicationFunction() {
|
|
12
14
|
return new steps_1.BuildFunction({
|
|
13
15
|
namespace: 'eas',
|
|
@@ -25,15 +27,29 @@ function createLaunchApplicationFunction() {
|
|
|
25
27
|
required: false,
|
|
26
28
|
allowedValueTypeName: steps_1.BuildStepInputValueTypeName.STRING,
|
|
27
29
|
}),
|
|
30
|
+
steps_1.BuildStepInput.createProvider({
|
|
31
|
+
id: 'launch_args',
|
|
32
|
+
required: false,
|
|
33
|
+
allowedValueTypeName: steps_1.BuildStepInputValueTypeName.JSON,
|
|
34
|
+
}),
|
|
35
|
+
steps_1.BuildStepInput.createProvider({
|
|
36
|
+
id: 'open_url',
|
|
37
|
+
required: false,
|
|
38
|
+
allowedValueTypeName: steps_1.BuildStepInputValueTypeName.STRING,
|
|
39
|
+
}),
|
|
28
40
|
],
|
|
29
41
|
fn: async ({ global, logger }, { inputs, env }) => {
|
|
30
42
|
const applicationIdentifier = parseNonEmptyStringInput(inputs.application_identifier.value, 'application_identifier');
|
|
31
43
|
const activityName = inputs.activity_name.value === undefined
|
|
32
44
|
? undefined
|
|
33
45
|
: parseNonEmptyStringInput(inputs.activity_name.value, 'activity_name');
|
|
46
|
+
const launchArgs = parseLaunchArgsInput(inputs.launch_args.value);
|
|
47
|
+
const openUrl = inputs.open_url.value === undefined ? undefined : parseOpenUrlInput(inputs.open_url.value);
|
|
34
48
|
await launchApplicationAsync({
|
|
35
49
|
applicationIdentifier,
|
|
36
50
|
activityName,
|
|
51
|
+
launchArgs,
|
|
52
|
+
openUrl,
|
|
37
53
|
runtimePlatform: global.runtimePlatform,
|
|
38
54
|
env,
|
|
39
55
|
logger,
|
|
@@ -41,23 +57,70 @@ function createLaunchApplicationFunction() {
|
|
|
41
57
|
},
|
|
42
58
|
});
|
|
43
59
|
}
|
|
44
|
-
async function launchApplicationAsync({ applicationIdentifier, activityName, runtimePlatform, env, logger, }) {
|
|
60
|
+
async function launchApplicationAsync({ applicationIdentifier, activityName, launchArgs = [], openUrl, runtimePlatform, env, logger, }) {
|
|
45
61
|
if (runtimePlatform === steps_1.BuildRuntimePlatform.DARWIN) {
|
|
46
|
-
logger
|
|
47
|
-
await (0, turtle_spawn_1.default)('xcrun', ['simctl', 'launch', 'booted', applicationIdentifier], {
|
|
62
|
+
logApplicationLaunch(logger, applicationIdentifier, launchArgs);
|
|
63
|
+
await (0, turtle_spawn_1.default)('xcrun', ['simctl', 'launch', 'booted', applicationIdentifier, ...launchArgs], {
|
|
48
64
|
env,
|
|
49
65
|
logger,
|
|
50
66
|
});
|
|
67
|
+
if (openUrl) {
|
|
68
|
+
await preapproveIosUrlSchemeAsync({ applicationIdentifier, openUrl, env, logger });
|
|
69
|
+
logger.info(`Opening ${openUrl} in ${applicationIdentifier}.`);
|
|
70
|
+
await (0, turtle_spawn_1.default)('xcrun', ['simctl', 'openurl', 'booted', openUrl], { env, logger });
|
|
71
|
+
}
|
|
51
72
|
return;
|
|
52
73
|
}
|
|
53
74
|
if (!activityName) {
|
|
54
75
|
throw new eas_build_job_1.UserError('EAS_LAUNCH_APPLICATION_MISSING_ACTIVITY', 'Launching an Android application requires activity_name.');
|
|
55
76
|
}
|
|
56
|
-
logger
|
|
57
|
-
|
|
77
|
+
logApplicationLaunch(logger, applicationIdentifier, launchArgs);
|
|
78
|
+
// Android does not support process arguments like iOS. Pass raw `am start` Intent
|
|
79
|
+
// arguments instead, such as `--es key value` or `--ez key true`.
|
|
80
|
+
await (0, turtle_spawn_1.default)('adb', ['shell', 'am', 'start', ...launchArgs, '-n', `${applicationIdentifier}/${activityName}`], {
|
|
58
81
|
env,
|
|
59
82
|
logger,
|
|
60
83
|
});
|
|
84
|
+
if (openUrl) {
|
|
85
|
+
logger.info(`Opening ${openUrl} in ${applicationIdentifier}.`);
|
|
86
|
+
await (0, turtle_spawn_1.default)('adb', [
|
|
87
|
+
'shell',
|
|
88
|
+
'am',
|
|
89
|
+
'start',
|
|
90
|
+
'-a',
|
|
91
|
+
'android.intent.action.VIEW',
|
|
92
|
+
'-d',
|
|
93
|
+
openUrl,
|
|
94
|
+
'-n',
|
|
95
|
+
`${applicationIdentifier}/${activityName}`,
|
|
96
|
+
], { env, logger });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
async function preapproveIosUrlSchemeAsync({ applicationIdentifier, openUrl, env, logger, }) {
|
|
100
|
+
const urlScheme = new URL(openUrl).protocol.slice(0, -1);
|
|
101
|
+
if (urlScheme === 'http' || urlScheme === 'https') {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
try {
|
|
105
|
+
await (0, turtle_spawn_1.default)('xcrun', [
|
|
106
|
+
'simctl',
|
|
107
|
+
'spawn',
|
|
108
|
+
'booted',
|
|
109
|
+
'defaults',
|
|
110
|
+
'write',
|
|
111
|
+
IOS_URL_SCHEME_APPROVAL_DOMAIN,
|
|
112
|
+
`${IOS_URL_SCHEME_APPROVAL_KEY_PREFIX}${urlScheme}`,
|
|
113
|
+
'-string',
|
|
114
|
+
applicationIdentifier,
|
|
115
|
+
], { env, logger });
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
logger.warn({ err: error }, `Could not preapprove the ${urlScheme} URL scheme for ${applicationIdentifier}. Opening the URL anyway; the Simulator might require manual confirmation.`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function logApplicationLaunch(logger, applicationIdentifier, launchArgs) {
|
|
122
|
+
const argumentsDescription = launchArgs.length > 0 ? ` with arguments ${JSON.stringify(launchArgs)}` : '';
|
|
123
|
+
logger.info(`Launching ${applicationIdentifier}${argumentsDescription}.`);
|
|
61
124
|
}
|
|
62
125
|
function parseNonEmptyStringInput(value, inputName) {
|
|
63
126
|
if (typeof value !== 'string' || value.length === 0) {
|
|
@@ -65,3 +128,19 @@ function parseNonEmptyStringInput(value, inputName) {
|
|
|
65
128
|
}
|
|
66
129
|
return value;
|
|
67
130
|
}
|
|
131
|
+
function parseLaunchArgsInput(value) {
|
|
132
|
+
if (value === undefined) {
|
|
133
|
+
return [];
|
|
134
|
+
}
|
|
135
|
+
if (!Array.isArray(value) || !value.every(argument => typeof argument === 'string')) {
|
|
136
|
+
throw new eas_build_job_1.UserError('EAS_LAUNCH_APPLICATION_INVALID_INPUT', 'Input "launch_args" must be an array of strings.');
|
|
137
|
+
}
|
|
138
|
+
return value;
|
|
139
|
+
}
|
|
140
|
+
function parseOpenUrlInput(value) {
|
|
141
|
+
const openUrl = parseNonEmptyStringInput(value, 'open_url');
|
|
142
|
+
if (!URL.canParse(openUrl)) {
|
|
143
|
+
throw new eas_build_job_1.UserError('EAS_LAUNCH_APPLICATION_INVALID_INPUT', 'Input "open_url" must be a valid URL.');
|
|
144
|
+
}
|
|
145
|
+
return openUrl;
|
|
146
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type AppiumCommand } from './appiumCommands.generated';
|
|
2
|
+
export declare const APPIUM_COMMAND_SUMMARIES: Record<AppiumCommand, string>;
|
|
3
|
+
/**
|
|
4
|
+
* Translate a raw Appium command name into a short, human-readable summary.
|
|
5
|
+
*
|
|
6
|
+
* If a command has no curated summary, the raw command name is returned
|
|
7
|
+
* unchanged — we intentionally do not guess a phrasing.
|
|
8
|
+
*/
|
|
9
|
+
export declare function humanizeAppiumCommand(command: string): string;
|
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.APPIUM_COMMAND_SUMMARIES = void 0;
|
|
4
|
+
exports.humanizeAppiumCommand = humanizeAppiumCommand;
|
|
5
|
+
exports.APPIUM_COMMAND_SUMMARIES = {
|
|
6
|
+
// Session lifecycle
|
|
7
|
+
createSession: 'Started the session',
|
|
8
|
+
deleteSession: 'Ended the session',
|
|
9
|
+
getSession: 'Read the session details',
|
|
10
|
+
getStatus: 'Checked the server status',
|
|
11
|
+
getAppiumSessions: 'Listed Appium sessions',
|
|
12
|
+
getAppiumSessionCapabilities: 'Read the session capabilities',
|
|
13
|
+
getTimeouts: 'Read timeouts',
|
|
14
|
+
timeouts: 'Set timeouts',
|
|
15
|
+
getSettings: 'Read Appium settings',
|
|
16
|
+
updateSettings: 'Updated Appium settings',
|
|
17
|
+
listCommands: 'Listed available commands',
|
|
18
|
+
listExtensions: 'Listed available extensions',
|
|
19
|
+
receiveAsyncResponse: 'Received an async response',
|
|
20
|
+
// Screen and media
|
|
21
|
+
getScreenshot: 'Took a screenshot',
|
|
22
|
+
getElementScreenshot: 'Took a screenshot of an element',
|
|
23
|
+
getPageSource: 'Read the screen contents',
|
|
24
|
+
printPage: 'Printed the page',
|
|
25
|
+
// Window and orientation
|
|
26
|
+
getWindowRect: 'Read the screen size',
|
|
27
|
+
setWindowRect: 'Resized the window',
|
|
28
|
+
maximizeWindow: 'Maximized the window',
|
|
29
|
+
minimizeWindow: 'Minimized the window',
|
|
30
|
+
fullScreenWindow: 'Made the window full screen',
|
|
31
|
+
getWindowHandle: 'Read the current window',
|
|
32
|
+
getWindowHandles: 'Listed open windows',
|
|
33
|
+
setWindow: 'Switched window',
|
|
34
|
+
closeWindow: 'Closed the window',
|
|
35
|
+
createNewWindow: 'Opened a new window',
|
|
36
|
+
setFrame: 'Switched to a frame',
|
|
37
|
+
switchToParentFrame: 'Switched to the parent frame',
|
|
38
|
+
getOrientation: 'Read the screen orientation',
|
|
39
|
+
setOrientation: 'Changed the screen orientation',
|
|
40
|
+
getRotation: 'Read the device rotation',
|
|
41
|
+
setRotation: 'Rotated the device',
|
|
42
|
+
// Device
|
|
43
|
+
getDeviceTime: 'Read the device time',
|
|
44
|
+
getGeoLocation: 'Read the device location',
|
|
45
|
+
setGeoLocation: 'Set the device location',
|
|
46
|
+
getNetworkConnection: 'Read the network connection',
|
|
47
|
+
setNetworkConnection: 'Changed the network connection',
|
|
48
|
+
setDevicePosture: 'Set the device posture',
|
|
49
|
+
clearDevicePosture: 'Cleared the device posture',
|
|
50
|
+
setPermissions: 'Set app permissions',
|
|
51
|
+
// Element discovery
|
|
52
|
+
findElement: 'Found an element',
|
|
53
|
+
findElements: 'Found elements',
|
|
54
|
+
findElementFromElement: 'Found a nested element',
|
|
55
|
+
findElementsFromElement: 'Found nested elements',
|
|
56
|
+
findElementFromShadowRoot: 'Found an element in a shadow root',
|
|
57
|
+
findElementsFromShadowRoot: 'Found elements in a shadow root',
|
|
58
|
+
elementShadowRoot: 'Read an element shadow root',
|
|
59
|
+
active: 'Read the focused element',
|
|
60
|
+
// Element interaction
|
|
61
|
+
click: 'Tapped an element',
|
|
62
|
+
clear: 'Cleared an element',
|
|
63
|
+
setValue: 'Typed into an element',
|
|
64
|
+
getText: 'Read element text',
|
|
65
|
+
getName: 'Read an element tag',
|
|
66
|
+
getAttribute: 'Read an element attribute',
|
|
67
|
+
getProperty: 'Read an element property',
|
|
68
|
+
getCssProperty: 'Read an element style',
|
|
69
|
+
getComputedLabel: 'Read an element label',
|
|
70
|
+
getComputedRole: 'Read an element role',
|
|
71
|
+
getElementRect: 'Read an element position and size',
|
|
72
|
+
elementDisplayed: 'Checked if an element was visible',
|
|
73
|
+
elementEnabled: 'Checked if an element was enabled',
|
|
74
|
+
elementSelected: 'Checked if an element was selected',
|
|
75
|
+
// Gestures
|
|
76
|
+
performActions: 'Performed a gesture',
|
|
77
|
+
releaseActions: 'Finished a gesture',
|
|
78
|
+
// App management
|
|
79
|
+
installApp: 'Installed an app',
|
|
80
|
+
removeApp: 'Removed an app',
|
|
81
|
+
isAppInstalled: 'Checked if an app was installed',
|
|
82
|
+
activateApp: 'Activated an app',
|
|
83
|
+
terminateApp: 'Terminated an app',
|
|
84
|
+
queryAppState: 'Read the app state',
|
|
85
|
+
background: 'Sent the app to the background',
|
|
86
|
+
// Contexts
|
|
87
|
+
getContexts: 'Listed available contexts',
|
|
88
|
+
getCurrentContext: 'Read the current context',
|
|
89
|
+
setContext: 'Switched context',
|
|
90
|
+
// Web navigation
|
|
91
|
+
setUrl: 'Opened a URL',
|
|
92
|
+
getUrl: 'Read the current URL',
|
|
93
|
+
back: 'Navigated back',
|
|
94
|
+
forward: 'Navigated forward',
|
|
95
|
+
refresh: 'Refreshed the page',
|
|
96
|
+
title: 'Read the page title',
|
|
97
|
+
// Cookies
|
|
98
|
+
getCookie: 'Read a cookie',
|
|
99
|
+
getCookies: 'Read all cookies',
|
|
100
|
+
setCookie: 'Set a cookie',
|
|
101
|
+
deleteCookie: 'Deleted a cookie',
|
|
102
|
+
deleteCookies: 'Deleted all cookies',
|
|
103
|
+
// Alerts
|
|
104
|
+
getAlertText: 'Read an alert',
|
|
105
|
+
setAlertText: 'Typed into an alert',
|
|
106
|
+
postAcceptAlert: 'Accepted an alert',
|
|
107
|
+
postDismissAlert: 'Dismissed an alert',
|
|
108
|
+
// Keyboard and input methods
|
|
109
|
+
hideKeyboard: 'Hid the keyboard',
|
|
110
|
+
isKeyboardShown: 'Checked if the keyboard was shown',
|
|
111
|
+
activateIMEEngine: 'Activated an input method',
|
|
112
|
+
deactivateIMEEngine: 'Deactivated the input method',
|
|
113
|
+
getActiveIMEEngine: 'Read the active input method',
|
|
114
|
+
availableIMEEngines: 'Listed input methods',
|
|
115
|
+
isIMEActivated: 'Checked if an input method was active',
|
|
116
|
+
// Clipboard (driver-level, not declared by base-driver)
|
|
117
|
+
getClipboard: 'Read the clipboard',
|
|
118
|
+
setClipboard: 'Wrote to the clipboard',
|
|
119
|
+
// Files
|
|
120
|
+
pushFile: 'Pushed a file to the device',
|
|
121
|
+
pullFile: 'Pulled a file from the device',
|
|
122
|
+
pullFolder: 'Pulled a folder from the device',
|
|
123
|
+
// Logs
|
|
124
|
+
getLog: 'Read device logs',
|
|
125
|
+
getLogTypes: 'Listed log types',
|
|
126
|
+
getLogEvents: 'Read logged events',
|
|
127
|
+
logCustomEvent: 'Logged a custom event',
|
|
128
|
+
generateTestReport: 'Generated a test report',
|
|
129
|
+
// Scripts
|
|
130
|
+
execute: 'Ran a script command',
|
|
131
|
+
executeAsync: 'Ran an async script command',
|
|
132
|
+
executeCdp: 'Ran a Chrome DevTools command',
|
|
133
|
+
// Web authentication (virtual authenticators)
|
|
134
|
+
addVirtualAuthenticator: 'Added a virtual authenticator',
|
|
135
|
+
removeVirtualAuthenticator: 'Removed a virtual authenticator',
|
|
136
|
+
addAuthCredential: 'Added an auth credential',
|
|
137
|
+
getAuthCredential: 'Read auth credentials',
|
|
138
|
+
removeAuthCredential: 'Removed an auth credential',
|
|
139
|
+
removeAllAuthCredentials: 'Removed all auth credentials',
|
|
140
|
+
setUserAuthVerified: 'Set the user verification state',
|
|
141
|
+
// Federated sign-in (FedCM)
|
|
142
|
+
fedCMGetAccounts: 'Listed federated sign-in accounts',
|
|
143
|
+
fedCMSelectAccount: 'Selected a federated sign-in account',
|
|
144
|
+
fedCMGetDialogType: 'Read the federated sign-in dialog type',
|
|
145
|
+
fedCMGetTitle: 'Read the federated sign-in dialog title',
|
|
146
|
+
fedCMClickDialogButton: 'Clicked a federated sign-in dialog button',
|
|
147
|
+
fedCMCancelDialog: 'Canceled the federated sign-in dialog',
|
|
148
|
+
fedCMResetCooldown: 'Reset the federated sign-in cooldown',
|
|
149
|
+
fedCMSetDelayEnabled: 'Toggled the federated sign-in delay',
|
|
150
|
+
// Virtual sensors and pressure sources
|
|
151
|
+
createVirtualSensor: 'Created a virtual sensor',
|
|
152
|
+
updateVirtualSensorReading: 'Updated a virtual sensor reading',
|
|
153
|
+
getVirtualSensorInfo: 'Read virtual sensor info',
|
|
154
|
+
deleteVirtualSensor: 'Removed a virtual sensor',
|
|
155
|
+
createVirtualPressureSource: 'Created a virtual pressure source',
|
|
156
|
+
updateVirtualPressureSource: 'Updated a virtual pressure source',
|
|
157
|
+
deleteVirtualPressureSource: 'Removed a virtual pressure source',
|
|
158
|
+
// Privacy / experimental web platform
|
|
159
|
+
getGlobalPrivacyControl: 'Read the Global Privacy Control setting',
|
|
160
|
+
setGlobalPrivacyControl: 'Set the Global Privacy Control setting',
|
|
161
|
+
setStorageAccess: 'Set storage access',
|
|
162
|
+
setRPHRegistrationMode: 'Set the protocol handler registration mode',
|
|
163
|
+
setSPCTransactionMode: 'Set the payment transaction mode',
|
|
164
|
+
// Driver routes and compatibility commands
|
|
165
|
+
asyncScriptTimeout: 'Set the async script timeout',
|
|
166
|
+
closeApp: 'Closed the app',
|
|
167
|
+
disableConditionInducer: 'Disabled the condition inducer',
|
|
168
|
+
enableConditionInducer: 'Enabled the condition inducer',
|
|
169
|
+
fingerprint: 'Simulated a fingerprint',
|
|
170
|
+
getCurrentActivity: 'Read the current activity',
|
|
171
|
+
getCurrentPackage: 'Read the current package',
|
|
172
|
+
getDisplayDensity: 'Read the display density',
|
|
173
|
+
getLocation: 'Read an element location',
|
|
174
|
+
getLocationInView: 'Read an element location in view',
|
|
175
|
+
getPerformanceData: 'Read performance data',
|
|
176
|
+
getPerformanceDataTypes: 'Listed performance data types',
|
|
177
|
+
getScreenInfo: 'Read screen information',
|
|
178
|
+
getSize: 'Read an element size',
|
|
179
|
+
getStrings: 'Read app strings',
|
|
180
|
+
getSystemBars: 'Read system bar information',
|
|
181
|
+
getViewportRect: 'Read the viewport size',
|
|
182
|
+
getViewportScreenshot: 'Took a viewport screenshot',
|
|
183
|
+
getWindowSize: 'Read the window size',
|
|
184
|
+
gsmCall: 'Simulated a phone call',
|
|
185
|
+
gsmSignal: 'Changed the cellular signal',
|
|
186
|
+
gsmVoice: 'Changed the cellular voice state',
|
|
187
|
+
implicitWait: 'Set the element lookup timeout',
|
|
188
|
+
isLocationServicesEnabled: 'Checked if location services were enabled',
|
|
189
|
+
isLocked: 'Checked if the device was locked',
|
|
190
|
+
keyevent: 'Sent a key event',
|
|
191
|
+
keys: 'Sent keyboard input',
|
|
192
|
+
launchApp: 'Launched the app',
|
|
193
|
+
listConditionInducers: 'Listed condition inducers',
|
|
194
|
+
lock: 'Locked the device',
|
|
195
|
+
longPressKeyCode: 'Long-pressed a key',
|
|
196
|
+
networkSpeed: 'Changed the network speed',
|
|
197
|
+
openNotifications: 'Opened notifications',
|
|
198
|
+
powerAC: 'Changed the charging state',
|
|
199
|
+
powerCapacity: 'Changed the battery level',
|
|
200
|
+
pressKeyCode: 'Pressed a key',
|
|
201
|
+
replaceValue: 'Replaced an element value',
|
|
202
|
+
reset: 'Reset the app',
|
|
203
|
+
sendSMS: 'Simulated a text message',
|
|
204
|
+
sensorSet: 'Changed a sensor value',
|
|
205
|
+
setStylusHandwriting: 'Changed stylus handwriting mode',
|
|
206
|
+
setValueImmediate: 'Typed into an element immediately',
|
|
207
|
+
startActivity: 'Started an activity',
|
|
208
|
+
startAudioRecording: 'Started audio recording',
|
|
209
|
+
startRecordingScreen: 'Started screen recording',
|
|
210
|
+
stopAudioRecording: 'Stopped audio recording',
|
|
211
|
+
stopRecordingScreen: 'Stopped screen recording',
|
|
212
|
+
submit: 'Submitted an element',
|
|
213
|
+
toggleData: 'Toggled mobile data',
|
|
214
|
+
toggleEnrollTouchId: 'Changed Touch ID enrollment',
|
|
215
|
+
toggleFlightMode: 'Toggled airplane mode',
|
|
216
|
+
toggleLocationServices: 'Toggled location services',
|
|
217
|
+
toggleWiFi: 'Toggled Wi-Fi',
|
|
218
|
+
touchId: 'Simulated Touch ID',
|
|
219
|
+
unlock: 'Unlocked the device',
|
|
220
|
+
// Driver mobile commands
|
|
221
|
+
mobileAcceptAlert: 'Accepted an alert',
|
|
222
|
+
mobileActivateApp: 'Activated an app',
|
|
223
|
+
mobileBackgroundApp: 'Sent the app to the background',
|
|
224
|
+
mobileBluetooth: 'Changed Bluetooth state',
|
|
225
|
+
mobileBroadcast: 'Sent an Android broadcast',
|
|
226
|
+
mobileCalibrateWebToRealCoordinatesTranslation: 'Calibrated web coordinates',
|
|
227
|
+
mobileChangePermissions: 'Changed app permissions',
|
|
228
|
+
mobileClearApp: 'Cleared app data',
|
|
229
|
+
mobileClearKeychains: 'Cleared keychains',
|
|
230
|
+
mobileClickGesture: 'Performed a click gesture',
|
|
231
|
+
mobileConfigureLocalization: 'Changed device localization',
|
|
232
|
+
mobileDeepLink: 'Opened a deep link',
|
|
233
|
+
mobileDeleteFile: 'Deleted a device file',
|
|
234
|
+
mobileDeleteFolder: 'Deleted a device folder',
|
|
235
|
+
mobileDeviceidle: 'Changed device idle state',
|
|
236
|
+
mobileDisableVoiceOver: 'Disabled VoiceOver',
|
|
237
|
+
mobileDismissAlert: 'Dismissed an alert',
|
|
238
|
+
mobileDoubleClickGesture: 'Performed a double-click gesture',
|
|
239
|
+
mobileDoubleTap: 'Double-tapped the screen',
|
|
240
|
+
mobileDragFromToForDuration: 'Dragged between screen points',
|
|
241
|
+
mobileDragFromToWithVelocity: 'Dragged with a set velocity',
|
|
242
|
+
mobileDragGesture: 'Performed a drag gesture',
|
|
243
|
+
mobileEnableVoiceOver: 'Enabled VoiceOver',
|
|
244
|
+
mobileEnrollBiometric: 'Changed biometric enrollment',
|
|
245
|
+
mobileExecEmuConsoleCommand: 'Ran an emulator console command',
|
|
246
|
+
mobileExpectNotification: 'Waited for a notification',
|
|
247
|
+
mobileFingerprint: 'Simulated a fingerprint',
|
|
248
|
+
mobileFlingGesture: 'Performed a fling gesture',
|
|
249
|
+
mobileForcePress: 'Force-pressed the screen',
|
|
250
|
+
mobileGetActionHistory: 'Read scheduled action history',
|
|
251
|
+
mobileGetActiveAppInfo: 'Read active app information',
|
|
252
|
+
mobileGetAppearance: 'Read the device appearance',
|
|
253
|
+
mobileGetBatteryInfo: 'Read battery information',
|
|
254
|
+
mobileGetChromeCapabilities: 'Read Chrome capabilities',
|
|
255
|
+
mobileGetConnectivity: 'Read device connectivity',
|
|
256
|
+
mobileGetContentSize: 'Read scrollable content size',
|
|
257
|
+
mobileGetContexts: 'Listed available contexts',
|
|
258
|
+
mobileGetDeviceInfo: 'Read device information',
|
|
259
|
+
mobileGetDeviceTime: 'Read the device time',
|
|
260
|
+
mobileGetDeclaredOrientation: 'Read the declared device orientation',
|
|
261
|
+
mobileGetGeolocation: 'Read the device location',
|
|
262
|
+
mobileGetIncreaseContrast: 'Read the Increase Contrast setting',
|
|
263
|
+
mobileGetNotifications: 'Read notifications',
|
|
264
|
+
mobileGetPasteboard: 'Read the pasteboard',
|
|
265
|
+
mobileGetPerformanceData: 'Read app performance data',
|
|
266
|
+
mobileGetPermission: 'Read an app permission',
|
|
267
|
+
mobileGetPermissions: 'Read app permissions',
|
|
268
|
+
mobileGetSimulatedLocation: 'Read the simulated location',
|
|
269
|
+
mobileGetSource: 'Read the screen contents',
|
|
270
|
+
mobileGetUiMode: 'Read the Android UI mode',
|
|
271
|
+
mobileGetXctestScreenRecordingInfo: 'Read XCTest screen recording information',
|
|
272
|
+
mobileGsmCall: 'Simulated a phone call',
|
|
273
|
+
mobileGsmSignal: 'Changed the cellular signal',
|
|
274
|
+
mobileGsmVoice: 'Changed the cellular voice state',
|
|
275
|
+
mobileHandleAlert: 'Handled an alert',
|
|
276
|
+
mobileHideKeyboard: 'Hid the keyboard',
|
|
277
|
+
mobileInjectEmulatorCameraImage: 'Injected an emulator camera image',
|
|
278
|
+
mobileInstallApp: 'Installed an app',
|
|
279
|
+
mobileInstallCertificate: 'Installed a certificate',
|
|
280
|
+
mobileInstallMultipleApks: 'Installed multiple APKs',
|
|
281
|
+
mobileInstallXCTestBundle: 'Installed an XCTest bundle',
|
|
282
|
+
mobileIsAppInstalled: 'Checked if an app was installed',
|
|
283
|
+
mobileIsBiometricEnrolled: 'Checked biometric enrollment',
|
|
284
|
+
mobileIsMediaProjectionRecordingRunning: 'Checked media projection recording',
|
|
285
|
+
mobileIsVoiceOverEnabled: 'Checked if VoiceOver was enabled',
|
|
286
|
+
mobileKeys: 'Sent keyboard input',
|
|
287
|
+
mobileKillApp: 'Stopped an app',
|
|
288
|
+
mobileLaunchApp: 'Launched an app',
|
|
289
|
+
mobileListApps: 'Listed installed apps',
|
|
290
|
+
mobileListCertificates: 'Listed certificates',
|
|
291
|
+
mobileListDisplays: 'Listed displays',
|
|
292
|
+
mobileListSms: 'Listed text messages',
|
|
293
|
+
mobileListWindows: 'Listed app windows',
|
|
294
|
+
mobileListXCTestBundles: 'Listed XCTest bundles',
|
|
295
|
+
mobileLongClickGesture: 'Performed a long-click gesture',
|
|
296
|
+
mobileNetworkSpeed: 'Changed the network speed',
|
|
297
|
+
mobileNfc: 'Changed NFC state',
|
|
298
|
+
mobilePerformAccessibilityAudit: 'Ran an accessibility audit',
|
|
299
|
+
mobilePerformEditorAction: 'Performed a keyboard editor action',
|
|
300
|
+
mobilePerformHandGesture: 'Performed a hand gesture',
|
|
301
|
+
mobilePerformIndigoHidEvent: 'Performed an Indigo HID event',
|
|
302
|
+
mobilePerformIoHidEvent: 'Performed an IOHID event',
|
|
303
|
+
mobilePerformStatusBarCommand: 'Performed a status bar command',
|
|
304
|
+
mobilePinch: 'Pinched the screen',
|
|
305
|
+
mobilePinchCloseGesture: 'Performed a pinch-close gesture',
|
|
306
|
+
mobilePinchOpenGesture: 'Performed a pinch-open gesture',
|
|
307
|
+
mobilePowerAc: 'Changed the charging state',
|
|
308
|
+
mobilePowerCapacity: 'Changed the battery level',
|
|
309
|
+
mobilePressButton: 'Pressed a device button',
|
|
310
|
+
mobilePressKey: 'Pressed a key',
|
|
311
|
+
mobilePullFile: 'Pulled a file from the device',
|
|
312
|
+
mobilePullFolder: 'Pulled a folder from the device',
|
|
313
|
+
mobilePushFile: 'Pushed a file to the device',
|
|
314
|
+
mobilePushNotification: 'Sent a push notification',
|
|
315
|
+
mobileQueryAppState: 'Read the app state',
|
|
316
|
+
mobileRefreshGpsCache: 'Refreshed the GPS cache',
|
|
317
|
+
mobileRemoveApp: 'Removed an app',
|
|
318
|
+
mobileRemoveCertificate: 'Removed a certificate',
|
|
319
|
+
mobileReplaceElementValue: 'Replaced an element value',
|
|
320
|
+
mobileResetAccessibilityCache: 'Reset the accessibility cache',
|
|
321
|
+
mobileResetGeolocation: 'Reset the device location',
|
|
322
|
+
mobileResetLocationService: 'Reset location services',
|
|
323
|
+
mobileResetPermission: 'Reset an app permission',
|
|
324
|
+
mobileResetSimulatedLocation: 'Reset the simulated location',
|
|
325
|
+
mobileRotateDigitalCrown: 'Rotated the Digital Crown',
|
|
326
|
+
mobileRotateElement: 'Rotated an element',
|
|
327
|
+
mobileRunXCTest: 'Ran an XCTest bundle',
|
|
328
|
+
mobileScheduleAction: 'Scheduled a device action',
|
|
329
|
+
mobileScreenshots: 'Took display screenshots',
|
|
330
|
+
mobileScroll: 'Scrolled the screen',
|
|
331
|
+
mobileScrollBackTo: 'Scrolled back to an element',
|
|
332
|
+
mobileScrollGesture: 'Performed a scroll gesture',
|
|
333
|
+
mobileScrollToElement: 'Scrolled to an element',
|
|
334
|
+
mobileSelectPickerWheelValue: 'Changed a picker wheel value',
|
|
335
|
+
mobileSendBiometricMatch: 'Simulated biometric authentication',
|
|
336
|
+
mobileSendMemoryWarning: 'Sent a memory warning',
|
|
337
|
+
mobileSendSms: 'Simulated a text message',
|
|
338
|
+
mobileSendTrimMemory: 'Sent an Android memory trim event',
|
|
339
|
+
mobileSetAppearance: 'Changed the device appearance',
|
|
340
|
+
mobileSetConnectivity: 'Changed device connectivity',
|
|
341
|
+
mobileSetContentSize: 'Changed the content size',
|
|
342
|
+
mobileSetGeolocation: 'Set the device location',
|
|
343
|
+
mobileSetIncreaseContrast: 'Changed the Increase Contrast setting',
|
|
344
|
+
mobileSetPasteboard: 'Wrote to the pasteboard',
|
|
345
|
+
mobileSetPermissions: 'Set app permissions',
|
|
346
|
+
mobileSetSimulatedLocation: 'Set a simulated location',
|
|
347
|
+
mobileSetUiMode: 'Changed the Android UI mode',
|
|
348
|
+
mobileShake: 'Shook the device',
|
|
349
|
+
mobileShell: 'Ran an Android shell command',
|
|
350
|
+
mobileSimctl: 'Ran a simctl command',
|
|
351
|
+
mobileSiriCommand: 'Sent a Siri command',
|
|
352
|
+
mobileStartActivity: 'Started an activity',
|
|
353
|
+
mobileStartLogsBroadcast: 'Started log streaming',
|
|
354
|
+
mobileStartMediaProjectionRecording: 'Started media projection recording',
|
|
355
|
+
mobileStartNetworkMonitor: 'Started network monitoring',
|
|
356
|
+
mobileStartPerfRecord: 'Started performance recording',
|
|
357
|
+
mobileStartScreenRecording: 'Started screen recording',
|
|
358
|
+
mobileStartScreenStreaming: 'Started screen streaming',
|
|
359
|
+
mobileStartService: 'Started a service',
|
|
360
|
+
mobileStartSystemMonitor: 'Started system monitoring',
|
|
361
|
+
mobileStartXctestScreenRecording: 'Started XCTest screen recording',
|
|
362
|
+
mobileStopLogsBroadcast: 'Stopped log streaming',
|
|
363
|
+
mobileStopMediaProjectionRecording: 'Stopped media projection recording',
|
|
364
|
+
mobileStopNetworkMonitor: 'Stopped network monitoring',
|
|
365
|
+
mobileStopPerfRecord: 'Stopped performance recording',
|
|
366
|
+
mobileStopScreenRecording: 'Stopped screen recording',
|
|
367
|
+
mobileStopScreenStreaming: 'Stopped screen streaming',
|
|
368
|
+
mobileStopService: 'Stopped a service',
|
|
369
|
+
mobileStopSystemMonitor: 'Stopped system monitoring',
|
|
370
|
+
mobileStopXctestScreenRecording: 'Stopped XCTest screen recording',
|
|
371
|
+
mobileSwipe: 'Swiped the screen',
|
|
372
|
+
mobileSwipeGesture: 'Performed a swipe gesture',
|
|
373
|
+
mobileTap: 'Tapped the screen',
|
|
374
|
+
mobileTapWithNumberOfTaps: 'Tapped the screen multiple times',
|
|
375
|
+
mobileTerminateApp: 'Terminated an app',
|
|
376
|
+
mobileTouchAndHold: 'Touched and held the screen',
|
|
377
|
+
mobileTwoFingerTap: 'Tapped with two fingers',
|
|
378
|
+
mobileType: 'Typed text',
|
|
379
|
+
mobileUnlock: 'Unlocked the device',
|
|
380
|
+
mobileUnscheduleAction: 'Canceled a scheduled action',
|
|
381
|
+
mobileUpdateSafariPreferences: 'Updated Safari preferences',
|
|
382
|
+
mobileViewPortRect: 'Read the viewport size',
|
|
383
|
+
mobileViewportScreenshot: 'Took a viewport screenshot',
|
|
384
|
+
mobileVoiceOverCurrentSpeech: 'Read current VoiceOver speech',
|
|
385
|
+
mobileVoiceOverMove: 'Moved the VoiceOver cursor',
|
|
386
|
+
};
|
|
387
|
+
/**
|
|
388
|
+
* Translate a raw Appium command name into a short, human-readable summary.
|
|
389
|
+
*
|
|
390
|
+
* If a command has no curated summary, the raw command name is returned
|
|
391
|
+
* unchanged — we intentionally do not guess a phrasing.
|
|
392
|
+
*/
|
|
393
|
+
function humanizeAppiumCommand(command) {
|
|
394
|
+
return Object.hasOwn(exports.APPIUM_COMMAND_SUMMARIES, command)
|
|
395
|
+
? exports.APPIUM_COMMAND_SUMMARIES[command]
|
|
396
|
+
: command;
|
|
397
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type BaseDriverAppiumCommand = 'activateApp' | 'activateIMEEngine' | 'active' | 'addAuthCredential' | 'addVirtualAuthenticator' | 'availableIMEEngines' | 'back' | 'clear' | 'clearDevicePosture' | 'click' | 'closeWindow' | 'createNewWindow' | 'createSession' | 'createVirtualPressureSource' | 'createVirtualSensor' | 'deactivateIMEEngine' | 'deleteCookie' | 'deleteCookies' | 'deleteSession' | 'deleteVirtualPressureSource' | 'deleteVirtualSensor' | 'elementDisplayed' | 'elementEnabled' | 'elementSelected' | 'elementShadowRoot' | 'execute' | 'executeAsync' | 'executeCdp' | 'fedCMCancelDialog' | 'fedCMClickDialogButton' | 'fedCMGetAccounts' | 'fedCMGetDialogType' | 'fedCMGetTitle' | 'fedCMResetCooldown' | 'fedCMSelectAccount' | 'fedCMSetDelayEnabled' | 'findElement' | 'findElementFromElement' | 'findElementFromShadowRoot' | 'findElements' | 'findElementsFromElement' | 'findElementsFromShadowRoot' | 'forward' | 'fullScreenWindow' | 'generateTestReport' | 'getActiveIMEEngine' | 'getAlertText' | 'getAppiumSessionCapabilities' | 'getAppiumSessions' | 'getAttribute' | 'getAuthCredential' | 'getComputedLabel' | 'getComputedRole' | 'getContexts' | 'getCookie' | 'getCookies' | 'getCssProperty' | 'getCurrentContext' | 'getDeviceTime' | 'getElementRect' | 'getElementScreenshot' | 'getGeoLocation' | 'getGlobalPrivacyControl' | 'getLog' | 'getLogEvents' | 'getLogTypes' | 'getName' | 'getNetworkConnection' | 'getOrientation' | 'getPageSource' | 'getProperty' | 'getRotation' | 'getScreenshot' | 'getSession' | 'getSettings' | 'getStatus' | 'getText' | 'getTimeouts' | 'getUrl' | 'getVirtualSensorInfo' | 'getWindowHandle' | 'getWindowHandles' | 'getWindowRect' | 'hideKeyboard' | 'installApp' | 'isAppInstalled' | 'isIMEActivated' | 'isKeyboardShown' | 'listCommands' | 'listExtensions' | 'logCustomEvent' | 'maximizeWindow' | 'minimizeWindow' | 'performActions' | 'postAcceptAlert' | 'postDismissAlert' | 'printPage' | 'pullFile' | 'pullFolder' | 'pushFile' | 'queryAppState' | 'receiveAsyncResponse' | 'refresh' | 'releaseActions' | 'removeAllAuthCredentials' | 'removeApp' | 'removeAuthCredential' | 'removeVirtualAuthenticator' | 'setAlertText' | 'setContext' | 'setCookie' | 'setDevicePosture' | 'setFrame' | 'setGeoLocation' | 'setGlobalPrivacyControl' | 'setNetworkConnection' | 'setOrientation' | 'setPermissions' | 'setRPHRegistrationMode' | 'setRotation' | 'setSPCTransactionMode' | 'setStorageAccess' | 'setUrl' | 'setUserAuthVerified' | 'setValue' | 'setWindow' | 'setWindowRect' | 'switchToParentFrame' | 'terminateApp' | 'timeouts' | 'title' | 'updateSettings' | 'updateVirtualPressureSource' | 'updateVirtualSensorReading';
|
|
2
|
+
export type XCUITestAppiumCommand = 'asyncScriptTimeout' | 'background' | 'closeApp' | 'disableConditionInducer' | 'enableConditionInducer' | 'getClipboard' | 'getLocation' | 'getLocationInView' | 'getScreenInfo' | 'getSize' | 'getStrings' | 'getViewportRect' | 'getViewportScreenshot' | 'getWindowSize' | 'implicitWait' | 'isLocked' | 'keys' | 'launchApp' | 'listConditionInducers' | 'lock' | 'mobileActivateApp' | 'mobileCalibrateWebToRealCoordinatesTranslation' | 'mobileClearApp' | 'mobileClearKeychains' | 'mobileConfigureLocalization' | 'mobileDeepLink' | 'mobileDeleteFile' | 'mobileDeleteFolder' | 'mobileDisableVoiceOver' | 'mobileDoubleTap' | 'mobileDragFromToForDuration' | 'mobileDragFromToWithVelocity' | 'mobileEnableVoiceOver' | 'mobileEnrollBiometric' | 'mobileExpectNotification' | 'mobileForcePress' | 'mobileGetActiveAppInfo' | 'mobileGetAppearance' | 'mobileGetBatteryInfo' | 'mobileGetContentSize' | 'mobileGetContexts' | 'mobileGetDeviceInfo' | 'mobileGetDeviceTime' | 'mobileGetIncreaseContrast' | 'mobileGetPasteboard' | 'mobileGetPermission' | 'mobileGetSimulatedLocation' | 'mobileGetSource' | 'mobileGetXctestScreenRecordingInfo' | 'mobileHandleAlert' | 'mobileHideKeyboard' | 'mobileInstallApp' | 'mobileInstallCertificate' | 'mobileInstallXCTestBundle' | 'mobileIsAppInstalled' | 'mobileIsBiometricEnrolled' | 'mobileIsVoiceOverEnabled' | 'mobileKeys' | 'mobileKillApp' | 'mobileLaunchApp' | 'mobileListApps' | 'mobileListCertificates' | 'mobileListXCTestBundles' | 'mobilePerformAccessibilityAudit' | 'mobilePerformHandGesture' | 'mobilePerformIndigoHidEvent' | 'mobilePerformIoHidEvent' | 'mobilePinch' | 'mobilePressButton' | 'mobilePullFile' | 'mobilePullFolder' | 'mobilePushFile' | 'mobilePushNotification' | 'mobileQueryAppState' | 'mobileRemoveApp' | 'mobileRemoveCertificate' | 'mobileResetLocationService' | 'mobileResetPermission' | 'mobileResetSimulatedLocation' | 'mobileRotateDigitalCrown' | 'mobileRotateElement' | 'mobileRunXCTest' | 'mobileScroll' | 'mobileScrollToElement' | 'mobileSelectPickerWheelValue' | 'mobileSendBiometricMatch' | 'mobileSendMemoryWarning' | 'mobileSetAppearance' | 'mobileSetContentSize' | 'mobileSetIncreaseContrast' | 'mobileSetPasteboard' | 'mobileSetPermissions' | 'mobileSetSimulatedLocation' | 'mobileShake' | 'mobileSimctl' | 'mobileSiriCommand' | 'mobileStartLogsBroadcast' | 'mobileStartNetworkMonitor' | 'mobileStartPerfRecord' | 'mobileStartScreenRecording' | 'mobileStartSystemMonitor' | 'mobileStartXctestScreenRecording' | 'mobileStopLogsBroadcast' | 'mobileStopNetworkMonitor' | 'mobileStopPerfRecord' | 'mobileStopScreenRecording' | 'mobileStopSystemMonitor' | 'mobileStopXctestScreenRecording' | 'mobileSwipe' | 'mobileTap' | 'mobileTapWithNumberOfTaps' | 'mobileTerminateApp' | 'mobileTouchAndHold' | 'mobileTwoFingerTap' | 'mobileUpdateSafariPreferences' | 'mobileVoiceOverCurrentSpeech' | 'mobileVoiceOverMove' | 'reset' | 'setClipboard' | 'setValueImmediate' | 'startAudioRecording' | 'startRecordingScreen' | 'stopAudioRecording' | 'stopRecordingScreen' | 'submit' | 'toggleEnrollTouchId' | 'touchId' | 'unlock';
|
|
3
|
+
export type UiAutomator2AppiumCommand = 'background' | 'fingerprint' | 'getClipboard' | 'getCurrentActivity' | 'getCurrentPackage' | 'getDisplayDensity' | 'getLocation' | 'getLocationInView' | 'getPerformanceData' | 'getPerformanceDataTypes' | 'getSize' | 'getStrings' | 'getSystemBars' | 'getWindowSize' | 'gsmCall' | 'gsmSignal' | 'gsmVoice' | 'implicitWait' | 'isLocationServicesEnabled' | 'isLocked' | 'keyevent' | 'keys' | 'lock' | 'longPressKeyCode' | 'mobileAcceptAlert' | 'mobileBackgroundApp' | 'mobileBluetooth' | 'mobileBroadcast' | 'mobileChangePermissions' | 'mobileClearApp' | 'mobileClickGesture' | 'mobileDeepLink' | 'mobileDeleteFile' | 'mobileDeviceidle' | 'mobileDismissAlert' | 'mobileDoubleClickGesture' | 'mobileDragGesture' | 'mobileExecEmuConsoleCommand' | 'mobileFingerprint' | 'mobileFlingGesture' | 'mobileGetActionHistory' | 'mobileGetBatteryInfo' | 'mobileGetChromeCapabilities' | 'mobileGetConnectivity' | 'mobileGetContexts' | 'mobileGetDeclaredOrientation' | 'mobileGetDeviceInfo' | 'mobileGetDeviceTime' | 'mobileGetGeolocation' | 'mobileGetNotifications' | 'mobileGetPerformanceData' | 'mobileGetPermissions' | 'mobileGetUiMode' | 'mobileGsmCall' | 'mobileGsmSignal' | 'mobileGsmVoice' | 'mobileInjectEmulatorCameraImage' | 'mobileInstallApp' | 'mobileInstallMultipleApks' | 'mobileIsAppInstalled' | 'mobileIsMediaProjectionRecordingRunning' | 'mobileListApps' | 'mobileListDisplays' | 'mobileListSms' | 'mobileListWindows' | 'mobileLongClickGesture' | 'mobileNetworkSpeed' | 'mobileNfc' | 'mobilePerformEditorAction' | 'mobilePerformStatusBarCommand' | 'mobilePinchCloseGesture' | 'mobilePinchOpenGesture' | 'mobilePowerAc' | 'mobilePowerCapacity' | 'mobilePressKey' | 'mobileRefreshGpsCache' | 'mobileRemoveApp' | 'mobileReplaceElementValue' | 'mobileResetAccessibilityCache' | 'mobileResetGeolocation' | 'mobileScheduleAction' | 'mobileScreenshots' | 'mobileScroll' | 'mobileScrollBackTo' | 'mobileScrollGesture' | 'mobileSendSms' | 'mobileSendTrimMemory' | 'mobileSetConnectivity' | 'mobileSetGeolocation' | 'mobileSetUiMode' | 'mobileShell' | 'mobileStartActivity' | 'mobileStartLogsBroadcast' | 'mobileStartMediaProjectionRecording' | 'mobileStartScreenStreaming' | 'mobileStartService' | 'mobileStopLogsBroadcast' | 'mobileStopMediaProjectionRecording' | 'mobileStopScreenStreaming' | 'mobileStopService' | 'mobileSwipeGesture' | 'mobileTerminateApp' | 'mobileType' | 'mobileUnlock' | 'mobileUnscheduleAction' | 'mobileViewPortRect' | 'mobileViewportScreenshot' | 'networkSpeed' | 'openNotifications' | 'powerAC' | 'powerCapacity' | 'pressKeyCode' | 'replaceValue' | 'sendSMS' | 'sensorSet' | 'setClipboard' | 'setStylusHandwriting' | 'setValueImmediate' | 'startActivity' | 'startRecordingScreen' | 'stopRecordingScreen' | 'toggleData' | 'toggleFlightMode' | 'toggleLocationServices' | 'toggleWiFi' | 'unlock';
|
|
4
|
+
export type AppiumCommand = BaseDriverAppiumCommand | XCUITestAppiumCommand | UiAutomator2AppiumCommand;
|
|
@@ -10,6 +10,7 @@ const node_path_1 = __importDefault(require("node:path"));
|
|
|
10
10
|
const promises_1 = require("node:timers/promises");
|
|
11
11
|
const zod_1 = require("zod");
|
|
12
12
|
const turtleFetch_1 = require("../../utils/turtleFetch");
|
|
13
|
+
const appiumCommandSummary_1 = require("./appiumCommandSummary");
|
|
13
14
|
const deviceRunSessionEvents_1 = require("./deviceRunSessionEvents");
|
|
14
15
|
const APPIUM_REQUEST_TIMEOUT_MS = 10_000;
|
|
15
16
|
const POLL_INTERVAL_MS = 1_000;
|
|
@@ -127,7 +128,7 @@ function createAppiumEventSource(eventFile) {
|
|
|
127
128
|
type: 'operation.completed',
|
|
128
129
|
operationId,
|
|
129
130
|
durationMs: Math.max(0, command.endTime - command.startTime),
|
|
130
|
-
summary: command.cmd,
|
|
131
|
+
summary: (0, appiumCommandSummary_1.humanizeAppiumCommand)(command.cmd),
|
|
131
132
|
data: {
|
|
132
133
|
command: command.cmd,
|
|
133
134
|
appiumSessionId: command.appiumSessionId,
|
|
@@ -3,6 +3,7 @@ import { z } from 'zod';
|
|
|
3
3
|
import { CustomBuildContext } from '../../customBuildContext';
|
|
4
4
|
declare const ArgentArtifactSchema: z.ZodObject<{
|
|
5
5
|
id: z.ZodString;
|
|
6
|
+
kind: z.ZodOptional<z.ZodString>;
|
|
6
7
|
filename: z.ZodString;
|
|
7
8
|
mimeType: z.ZodString;
|
|
8
9
|
isDirectory: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -21,11 +21,11 @@ const deviceRunSessionArtifacts_1 = require("./deviceRunSessionArtifacts");
|
|
|
21
21
|
const ARGENT_ARTIFACT_UPLOAD_POLL_INTERVAL_MS = 5_000;
|
|
22
22
|
const ARGENT_ARTIFACT_UPLOAD_CLEANUP_TIMEOUT_MS = 30_000;
|
|
23
23
|
const ARGENT_ARTIFACT_FETCH_TIMEOUT_MS = 10_000;
|
|
24
|
-
//
|
|
25
|
-
// renders specially
|
|
26
|
-
//
|
|
27
|
-
//
|
|
28
|
-
//
|
|
24
|
+
// Fallback kinds for Argent versions that do not include a semantic artifact kind. Only media types
|
|
25
|
+
// the EAS dashboard renders specially can be inferred safely. Note that these kinds only affect
|
|
26
|
+
// grouping and labelling. The dashboard gates its inline video player on the
|
|
27
|
+
// `__eas_screen_recording` metadata flag, which Argent artifacts deliberately do not set, so a
|
|
28
|
+
// `screen-recording` kind here does not add a player to the session page.
|
|
29
29
|
const ARGENT_ARTIFACT_KIND_BY_MIME_TYPE = new Map([
|
|
30
30
|
['image/png', 'screenshot'],
|
|
31
31
|
['image/jpeg', 'screenshot'],
|
|
@@ -34,6 +34,9 @@ const ARGENT_ARTIFACT_KIND_BY_MIME_TYPE = new Map([
|
|
|
34
34
|
]);
|
|
35
35
|
const ArgentArtifactSchema = zod_1.z.object({
|
|
36
36
|
id: zod_1.z.string(),
|
|
37
|
+
// Optional for compatibility with older Argent tool servers. Keep this open to new kinds so a
|
|
38
|
+
// newer Argent version can add a category without requiring an EAS worker release first.
|
|
39
|
+
kind: zod_1.z.string().optional(),
|
|
37
40
|
filename: zod_1.z.string(),
|
|
38
41
|
mimeType: zod_1.z.string(),
|
|
39
42
|
isDirectory: zod_1.z.boolean().optional(),
|
|
@@ -42,8 +45,12 @@ const ArgentArtifactsListResponseSchema = zod_1.z.object({
|
|
|
42
45
|
artifacts: zod_1.z.array(ArgentArtifactSchema),
|
|
43
46
|
});
|
|
44
47
|
function getArgentArtifactKind(artifact) {
|
|
48
|
+
if (artifact.kind) {
|
|
49
|
+
return artifact.kind;
|
|
50
|
+
}
|
|
45
51
|
// Directories are repackaged as a tarball before upload, so the reported media type describes the
|
|
46
|
-
// contents rather than the file we actually store.
|
|
52
|
+
// contents rather than the file we actually store. A semantic kind above remains valid because it
|
|
53
|
+
// describes what the artifact represents, not its transport format.
|
|
47
54
|
if (artifact.isDirectory) {
|
|
48
55
|
return undefined;
|
|
49
56
|
}
|
|
@@ -16,6 +16,7 @@ const os_1 = __importDefault(require("os"));
|
|
|
16
16
|
const path_1 = __importDefault(require("path"));
|
|
17
17
|
const zod_1 = require("zod");
|
|
18
18
|
const sentry_1 = require("../../../sentry");
|
|
19
|
+
const download_1 = require("../../../utils/download");
|
|
19
20
|
const DEFAULT_XCLOGPARSER_VERSION = 'v0.2.47';
|
|
20
21
|
const XCLOGPARSER_DOWNLOAD_URL = 'https://storage.googleapis.com/turtle-v2/xclogparser';
|
|
21
22
|
const XCLOGPARSER_DOWNLOAD_TIMEOUT_MS = 20_000;
|
|
@@ -123,7 +124,7 @@ async function downloadXclogparser({ tempDir, version, logger, proxyBaseUrl, env
|
|
|
123
124
|
const zipName = getXclogparserZipName(version);
|
|
124
125
|
const zipPath = path_1.default.join(tempDir, zipName);
|
|
125
126
|
const directUrl = `${XCLOGPARSER_DOWNLOAD_URL}/${zipName}`;
|
|
126
|
-
const proxiedUrl = getProxiedDownloadUrl({ directUrl, proxyBaseUrl });
|
|
127
|
+
const proxiedUrl = (0, download_1.getProxiedDownloadUrl)({ directUrl, proxyBaseUrl });
|
|
127
128
|
if (proxiedUrl) {
|
|
128
129
|
const proxiedDownloadResult = await (0, results_1.asyncResult)(downloadAndUnpackXclogparser({ tempDir, zipPath, sourceUrl: proxiedUrl, env }));
|
|
129
130
|
if (!proxiedDownloadResult.ok) {
|
|
@@ -188,13 +189,6 @@ const COMPILE_SIGNATURE_PREFIXES = ['SwiftCompile ', 'SwiftGeneratePch '];
|
|
|
188
189
|
function getXclogparserZipName(version) {
|
|
189
190
|
return `XCLogParser-macOS-x86-64-arm64-${version}.zip`;
|
|
190
191
|
}
|
|
191
|
-
function getProxiedDownloadUrl({ directUrl, proxyBaseUrl, }) {
|
|
192
|
-
if (!proxyBaseUrl) {
|
|
193
|
-
return null;
|
|
194
|
-
}
|
|
195
|
-
const parsedUrl = new URL(directUrl);
|
|
196
|
-
return directUrl.replace(`${parsedUrl.protocol}//${parsedUrl.host}`, `${proxyBaseUrl}/${parsedUrl.host}`);
|
|
197
|
-
}
|
|
198
192
|
function isCompileStep(step) {
|
|
199
193
|
const detailStepType = step.detailStepType ?? '';
|
|
200
194
|
const signature = step.signature ?? '';
|
|
@@ -27,6 +27,14 @@ export declare namespace IosSimulatorUtils {
|
|
|
27
27
|
runtimeDisplayName: string;
|
|
28
28
|
displayName: string;
|
|
29
29
|
};
|
|
30
|
+
export type IosSimulatorRuntime = {
|
|
31
|
+
identifier: string;
|
|
32
|
+
isAvailable?: boolean;
|
|
33
|
+
version?: string;
|
|
34
|
+
};
|
|
35
|
+
export function getAvailableRuntimesAsync({ env, }: {
|
|
36
|
+
env: NodeJS.ProcessEnv;
|
|
37
|
+
}): Promise<IosSimulatorRuntime[]>;
|
|
30
38
|
export function getAvailableDevicesAsync({ env, filter, }: {
|
|
31
39
|
env: NodeJS.ProcessEnv;
|
|
32
40
|
filter: 'available' | 'booted';
|
|
@@ -13,6 +13,15 @@ const promises_1 = require("node:timers/promises");
|
|
|
13
13
|
const retry_1 = require("./retry");
|
|
14
14
|
var IosSimulatorUtils;
|
|
15
15
|
(function (IosSimulatorUtils) {
|
|
16
|
+
async function getAvailableRuntimesAsync({ env, }) {
|
|
17
|
+
const { stdout } = await (0, turtle_spawn_1.default)('xcrun', ['simctl', 'list', 'runtimes', '--json'], { env });
|
|
18
|
+
const { runtimes } = JSON.parse(stdout);
|
|
19
|
+
return runtimes.flatMap(runtime => runtime.isAvailable !== false &&
|
|
20
|
+
runtime.identifier?.startsWith('com.apple.CoreSimulator.SimRuntime.iOS-')
|
|
21
|
+
? [{ ...runtime, identifier: runtime.identifier }]
|
|
22
|
+
: []);
|
|
23
|
+
}
|
|
24
|
+
IosSimulatorUtils.getAvailableRuntimesAsync = getAvailableRuntimesAsync;
|
|
16
25
|
async function getAvailableDevicesAsync({ env, filter, }) {
|
|
17
26
|
const result = await (0, turtle_spawn_1.default)('xcrun', ['simctl', 'list', 'devices', '--json', '--no-escape-slashes', filter], { env });
|
|
18
27
|
const xcrunData = JSON.parse(result.stdout);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getProxiedDownloadUrl = getProxiedDownloadUrl;
|
|
4
|
+
function getProxiedDownloadUrl({ directUrl, proxyBaseUrl, }) {
|
|
5
|
+
if (!proxyBaseUrl) {
|
|
6
|
+
return null;
|
|
7
|
+
}
|
|
8
|
+
const parsedUrl = new URL(directUrl);
|
|
9
|
+
return directUrl.replace(`${parsedUrl.protocol}//${parsedUrl.host}`, `${proxyBaseUrl.replace(/\/$/, '')}/${parsedUrl.host}`);
|
|
10
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@expo/build-tools",
|
|
3
|
-
"version": "22.
|
|
3
|
+
"version": "22.5.0",
|
|
4
4
|
"bugs": "https://github.com/expo/eas-cli/issues",
|
|
5
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"author": "Expo <support@expo.io>",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"build": "tsc",
|
|
26
26
|
"build:record-sim": "mkdir -p bin && record_sim_bin_path=$(swift build -c release --package-path resources/record-sim --build-path resources/record-sim/.build --show-bin-path) && swift build -c release --package-path resources/record-sim --build-path resources/record-sim/.build && cp \"$record_sim_bin_path/record-sim\" bin/record-sim && chmod +x bin/record-sim",
|
|
27
27
|
"typecheck": "tsc",
|
|
28
|
+
"generate-appium-commands": "mise exec node@22.22.0 -- node scripts/generate-appium-commands.js",
|
|
28
29
|
"prepack": "rimraf dist \"*.tsbuildinfo\" && yarn gql && tsc -p tsconfig.build.json",
|
|
29
30
|
"jest-unit": "jest --config jest/unit-config.ts",
|
|
30
31
|
"jest-integration": "jest --config jest/integration-config.ts",
|
|
@@ -46,7 +47,7 @@
|
|
|
46
47
|
"@expo/plist": "^0.3.5",
|
|
47
48
|
"@expo/results": "^1.0.0",
|
|
48
49
|
"@expo/spawn-async": "1.7.2",
|
|
49
|
-
"@expo/steps": "22.
|
|
50
|
+
"@expo/steps": "22.4.0",
|
|
50
51
|
"@expo/template-file": "22.0.0",
|
|
51
52
|
"@expo/turtle-spawn": "22.0.0",
|
|
52
53
|
"@expo/xcpretty": "^4.3.1",
|
|
@@ -102,5 +103,5 @@
|
|
|
102
103
|
"typescript": "^5.5.4",
|
|
103
104
|
"uuid": "^9.0.1"
|
|
104
105
|
},
|
|
105
|
-
"gitHead": "
|
|
106
|
+
"gitHead": "3f74ea369d329a363fe16c9f90c8be74cb598777"
|
|
106
107
|
}
|