@expo/build-tools 21.8.0 → 22.2.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/builders/common.js +4 -0
- package/dist/builders/ios.js +11 -6
- package/dist/steps/easFunctions.js +2 -0
- package/dist/steps/functions/installMaestro.d.ts +6 -1
- package/dist/steps/functions/installMaestro.js +181 -55
- package/dist/steps/functions/maestroBackend.d.ts +11 -0
- package/dist/steps/functions/maestroBackend.js +14 -0
- package/dist/steps/functions/maestroResultParser.d.ts +30 -0
- package/dist/steps/functions/maestroResultParser.js +78 -5
- package/dist/steps/functions/maestroScreenshots.d.ts +6 -0
- package/dist/steps/functions/maestroScreenshots.js +123 -0
- package/dist/steps/functions/maestroTests.js +187 -69
- package/dist/steps/functions/restoreBuildCache.js +2 -1
- package/dist/steps/functions/saveBuildCache.js +4 -2
- package/dist/steps/functions/saveCache.js +3 -0
- package/dist/steps/functions/startAgentDeviceRemoteSession.js +7 -0
- package/dist/steps/functions/startAppiumRemoteSession.d.ts +17 -0
- package/dist/steps/functions/startAppiumRemoteSession.js +244 -0
- package/dist/steps/functions/startArgentRemoteSession.js +7 -0
- package/dist/steps/functions/startServeSimRemoteSession.js +10 -1
- package/dist/steps/utils/appiumEvents.d.ts +10 -0
- package/dist/steps/utils/appiumEvents.js +175 -0
- package/dist/steps/utils/remoteDeviceRunSession.d.ts +2 -1
- package/dist/steps/utils/remoteDeviceRunSession.js +72 -46
- package/dist/utils/AndroidEmulatorUtils.d.ts +1 -0
- package/dist/utils/AndroidEmulatorUtils.js +46 -4
- package/dist/utils/sourceMaps.d.ts +5 -0
- package/dist/utils/sourceMaps.js +105 -0
- package/package.json +8 -8
|
@@ -11,9 +11,11 @@ const assert_1 = __importDefault(require("assert"));
|
|
|
11
11
|
const fast_glob_1 = __importDefault(require("fast-glob"));
|
|
12
12
|
const node_crypto_1 = require("node:crypto");
|
|
13
13
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
14
|
+
const node_net_1 = require("node:net");
|
|
14
15
|
const node_os_1 = __importDefault(require("node:os"));
|
|
15
16
|
const node_path_1 = __importDefault(require("node:path"));
|
|
16
17
|
const promises_1 = require("node:timers/promises");
|
|
18
|
+
const sentry_1 = require("../sentry");
|
|
17
19
|
const retry_1 = require("./retry");
|
|
18
20
|
var AndroidEmulatorUtils;
|
|
19
21
|
(function (AndroidEmulatorUtils) {
|
|
@@ -216,17 +218,21 @@ var AndroidEmulatorUtils;
|
|
|
216
218
|
AndroidEmulatorUtils.cloneAsync = cloneAsync;
|
|
217
219
|
async function startAsync({ deviceName, env, logcatDirectory, }) {
|
|
218
220
|
let logcatOutputPath;
|
|
221
|
+
let emulatorOutputPath;
|
|
219
222
|
try {
|
|
220
223
|
await node_fs_1.default.promises.mkdir(logcatDirectory, { recursive: true });
|
|
221
224
|
const safeDeviceName = deviceName.replace(/[^a-zA-Z0-9_.-]/g, '_');
|
|
222
225
|
const timestamp = Math.floor(Date.now() / 1000)
|
|
223
226
|
.toString(16)
|
|
224
227
|
.padStart(8, '0');
|
|
225
|
-
|
|
228
|
+
const outputName = `${safeDeviceName}-${timestamp}-${(0, node_crypto_1.randomBytes)(2).toString('hex')}`;
|
|
229
|
+
logcatOutputPath = node_path_1.default.join(logcatDirectory, `${outputName}-logcat.log`);
|
|
230
|
+
emulatorOutputPath = node_path_1.default.join(logcatDirectory, `${outputName}-emulator.log`);
|
|
226
231
|
await node_fs_1.default.promises.writeFile(logcatOutputPath, '');
|
|
232
|
+
await node_fs_1.default.promises.writeFile(emulatorOutputPath, '');
|
|
227
233
|
}
|
|
228
234
|
catch (err) {
|
|
229
|
-
throw new eas_build_job_1.SystemError(`Failed to prepare Android emulator
|
|
235
|
+
throw new eas_build_job_1.SystemError(`Failed to prepare Android emulator output for ${deviceName}.`, {
|
|
230
236
|
cause: err,
|
|
231
237
|
});
|
|
232
238
|
}
|
|
@@ -249,13 +255,49 @@ var AndroidEmulatorUtils;
|
|
|
249
255
|
: []),
|
|
250
256
|
], {
|
|
251
257
|
detached: true,
|
|
252
|
-
stdio: '
|
|
258
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
259
|
+
ignoreStdio: true,
|
|
253
260
|
env: {
|
|
254
261
|
...env,
|
|
255
262
|
// We don't need to wait for emulator to exit gracefully.
|
|
256
263
|
ANDROID_EMULATOR_WAIT_TIME_BEFORE_KILL: '1',
|
|
257
264
|
},
|
|
258
265
|
});
|
|
266
|
+
const emulatorOutputStream = node_fs_1.default.createWriteStream(emulatorOutputPath, { flags: 'a' });
|
|
267
|
+
let reportedEmulatorOutputError = false;
|
|
268
|
+
emulatorOutputStream.on('error', err => {
|
|
269
|
+
process.stderr.write(`Failed to write Android emulator output to ${emulatorOutputPath}: ${err}\n`);
|
|
270
|
+
if (!reportedEmulatorOutputError) {
|
|
271
|
+
reportedEmulatorOutputError = true;
|
|
272
|
+
sentry_1.Sentry.capture('Failed to write Android emulator process output', err, {
|
|
273
|
+
level: 'warning',
|
|
274
|
+
tags: {
|
|
275
|
+
errorCode: err.code ?? 'unknown',
|
|
276
|
+
},
|
|
277
|
+
extras: {
|
|
278
|
+
deviceName,
|
|
279
|
+
emulatorOutputPath,
|
|
280
|
+
},
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
// Only into the log file -- this process' stdout/stderr is not watched or uploaded.
|
|
285
|
+
emulatorPromise.child.stdout?.pipe(emulatorOutputStream, { end: false });
|
|
286
|
+
emulatorPromise.child.stderr?.pipe(emulatorOutputStream, { end: false });
|
|
287
|
+
emulatorPromise.child.once('close', () => {
|
|
288
|
+
emulatorOutputStream.end();
|
|
289
|
+
});
|
|
290
|
+
// Piped stdio creates socket handles in this process which, unlike inherited
|
|
291
|
+
// file descriptors, keep the event loop alive for as long as the emulator runs.
|
|
292
|
+
// We never stop the emulator explicitly, so without unref-ing these the process
|
|
293
|
+
// would never exit on its own -- defeating the `detached` + `unref()` below.
|
|
294
|
+
// Output is still captured for as long as this process lives.
|
|
295
|
+
if (emulatorPromise.child.stdout instanceof node_net_1.Socket) {
|
|
296
|
+
emulatorPromise.child.stdout.unref();
|
|
297
|
+
}
|
|
298
|
+
if (emulatorPromise.child.stderr instanceof node_net_1.Socket) {
|
|
299
|
+
emulatorPromise.child.stderr.unref();
|
|
300
|
+
}
|
|
259
301
|
// If emulator fails to start, throw its error.
|
|
260
302
|
if (!emulatorPromise.child.pid) {
|
|
261
303
|
await emulatorPromise;
|
|
@@ -276,7 +318,7 @@ var AndroidEmulatorUtils;
|
|
|
276
318
|
});
|
|
277
319
|
// We don't want to await the SpawnPromise here.
|
|
278
320
|
// eslint-disable-next-line @typescript-eslint/return-await
|
|
279
|
-
return { emulatorPromise, serialId, logcatOutputPath };
|
|
321
|
+
return { emulatorPromise, serialId, logcatOutputPath, emulatorOutputPath };
|
|
280
322
|
}
|
|
281
323
|
AndroidEmulatorUtils.startAsync = startAsync;
|
|
282
324
|
async function waitForReadyAsync({ serialId, env, timeoutMs = 3 * 60 * 1_000, logger, }) {
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { BuildJob } from '@expo/eas-build-job';
|
|
2
|
+
import { BuildContext } from '../context';
|
|
3
|
+
export declare function isSourceMapUploadEnabled(ctx: BuildContext<BuildJob>): boolean;
|
|
4
|
+
export declare function resolveIosSourceMapPathAsync(ctx: BuildContext<BuildJob>): Promise<string>;
|
|
5
|
+
export declare function maybeUploadSourceMapAsync(ctx: BuildContext<BuildJob>): Promise<void>;
|
|
@@ -0,0 +1,105 @@
|
|
|
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.isSourceMapUploadEnabled = isSourceMapUploadEnabled;
|
|
7
|
+
exports.resolveIosSourceMapPathAsync = resolveIosSourceMapPathAsync;
|
|
8
|
+
exports.maybeUploadSourceMapAsync = maybeUploadSourceMapAsync;
|
|
9
|
+
const eas_build_job_1 = require("@expo/eas-build-job");
|
|
10
|
+
const fast_glob_1 = __importDefault(require("fast-glob"));
|
|
11
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
12
|
+
const path_1 = __importDefault(require("path"));
|
|
13
|
+
const ANDROID_SOURCE_MAP_PATTERN = 'android/**/build/generated/sourcemaps/react/**/*.map';
|
|
14
|
+
const SOURCE_MAP_UPLOAD_DIRECTORY = 'observe-source-maps';
|
|
15
|
+
function isSourceMapUploadEnabled(ctx) {
|
|
16
|
+
return !ctx.isLocal && ctx.job.experimental?.uploadSourceMaps === true;
|
|
17
|
+
}
|
|
18
|
+
async function resolveIosSourceMapPathAsync(ctx) {
|
|
19
|
+
const configuredPath = ctx.env.SOURCEMAP_FILE;
|
|
20
|
+
const sourceMapPath = configuredPath
|
|
21
|
+
? path_1.default.resolve(ctx.getReactNativeProjectDirectory(), 'ios', configuredPath)
|
|
22
|
+
: path_1.default.join(ctx.workingdir, SOURCE_MAP_UPLOAD_DIRECTORY, 'main.jsbundle.map');
|
|
23
|
+
await fs_extra_1.default.ensureDir(path_1.default.dirname(sourceMapPath));
|
|
24
|
+
return sourceMapPath;
|
|
25
|
+
}
|
|
26
|
+
async function maybeUploadSourceMapAsync(ctx) {
|
|
27
|
+
if (!isSourceMapUploadEnabled(ctx)) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
const sourceMapPath = await resolveSourceMapPathAsync(ctx);
|
|
32
|
+
const strippedSourceMapPath = await stripSourcesContentAsync(ctx, sourceMapPath);
|
|
33
|
+
ctx.logger.info(`Uploading source map: ${sourceMapPath}`);
|
|
34
|
+
await ctx.uploadArtifact({
|
|
35
|
+
artifact: {
|
|
36
|
+
type: eas_build_job_1.ManagedArtifactType.SOURCE_MAP,
|
|
37
|
+
paths: [strippedSourceMapPath],
|
|
38
|
+
},
|
|
39
|
+
logger: ctx.logger,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
ctx.logger.warn({ err }, 'Failed to upload source map.');
|
|
44
|
+
ctx.markBuildPhaseHasWarnings();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async function resolveSourceMapPathAsync(ctx) {
|
|
48
|
+
if (ctx.job.platform === eas_build_job_1.Platform.IOS) {
|
|
49
|
+
const sourceMapPath = await resolveIosSourceMapPathAsync(ctx);
|
|
50
|
+
if (!(await fs_extra_1.default.pathExists(sourceMapPath))) {
|
|
51
|
+
throw new eas_build_job_1.SystemError(`The iOS source map was not generated at ${sourceMapPath}.`);
|
|
52
|
+
}
|
|
53
|
+
return sourceMapPath;
|
|
54
|
+
}
|
|
55
|
+
if (ctx.job.platform === eas_build_job_1.Platform.ANDROID) {
|
|
56
|
+
const projectDir = ctx.getReactNativeProjectDirectory();
|
|
57
|
+
const sourceMapPaths = (await (0, fast_glob_1.default)(ANDROID_SOURCE_MAP_PATTERN, {
|
|
58
|
+
absolute: true,
|
|
59
|
+
cwd: projectDir,
|
|
60
|
+
onlyFiles: true,
|
|
61
|
+
})).filter(sourceMapPath => !isIntermediateAndroidSourceMap(sourceMapPath));
|
|
62
|
+
if (sourceMapPaths.length === 0) {
|
|
63
|
+
throw new eas_build_job_1.SystemError('The Android build did not generate a final composed source map.');
|
|
64
|
+
}
|
|
65
|
+
if (sourceMapPaths.length > 1) {
|
|
66
|
+
throw new eas_build_job_1.SystemError(`Found multiple final Android source maps: ${sourceMapPaths.join(', ')}. ` +
|
|
67
|
+
'Refusing to upload a source map that may not match the application archive.');
|
|
68
|
+
}
|
|
69
|
+
return sourceMapPaths[0];
|
|
70
|
+
}
|
|
71
|
+
throw new eas_build_job_1.SystemError('Source-map upload is not supported for this build platform.');
|
|
72
|
+
}
|
|
73
|
+
function isIntermediateAndroidSourceMap(sourceMapPath) {
|
|
74
|
+
return sourceMapPath.endsWith('.packager.map') || sourceMapPath.endsWith('.compiler.map');
|
|
75
|
+
}
|
|
76
|
+
async function stripSourcesContentAsync(ctx, sourceMapPath) {
|
|
77
|
+
const sourceMap = JSON.parse(await fs_extra_1.default.readFile(sourceMapPath, 'utf8'));
|
|
78
|
+
if (!isRecord(sourceMap) || sourceMap.version !== 3) {
|
|
79
|
+
throw new eas_build_job_1.SystemError(`Invalid source map at ${sourceMapPath}.`);
|
|
80
|
+
}
|
|
81
|
+
removeSourcesContent(sourceMap);
|
|
82
|
+
const uploadDirectory = path_1.default.join(ctx.workingdir, SOURCE_MAP_UPLOAD_DIRECTORY);
|
|
83
|
+
const uploadPath = path_1.default.join(uploadDirectory, `${ctx.job.platform}.map`);
|
|
84
|
+
await fs_extra_1.default.ensureDir(uploadDirectory);
|
|
85
|
+
await fs_extra_1.default.writeFile(uploadPath, JSON.stringify(sourceMap), 'utf8');
|
|
86
|
+
return uploadPath;
|
|
87
|
+
}
|
|
88
|
+
function removeSourcesContent(value) {
|
|
89
|
+
if (Array.isArray(value)) {
|
|
90
|
+
for (const child of value) {
|
|
91
|
+
removeSourcesContent(child);
|
|
92
|
+
}
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (!isRecord(value)) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
delete value.sourcesContent;
|
|
99
|
+
for (const child of Object.values(value)) {
|
|
100
|
+
removeSourcesContent(child);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function isRecord(value) {
|
|
104
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
105
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@expo/build-tools",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "22.2.0",
|
|
4
4
|
"bugs": "https://github.com/expo/eas-cli/issues",
|
|
5
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"author": "Expo <support@expo.io>",
|
|
@@ -38,17 +38,17 @@
|
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@expo/config": "55.0.10",
|
|
40
40
|
"@expo/config-plugins": "55.0.7",
|
|
41
|
-
"@expo/downloader": "
|
|
42
|
-
"@expo/eas-build-job": "
|
|
41
|
+
"@expo/downloader": "22.0.0",
|
|
42
|
+
"@expo/eas-build-job": "22.0.0",
|
|
43
43
|
"@expo/env": "^0.4.0",
|
|
44
|
-
"@expo/logger": "
|
|
44
|
+
"@expo/logger": "22.0.0",
|
|
45
45
|
"@expo/package-manager": "1.9.10",
|
|
46
46
|
"@expo/plist": "^0.3.5",
|
|
47
47
|
"@expo/results": "^1.0.0",
|
|
48
48
|
"@expo/spawn-async": "1.7.2",
|
|
49
|
-
"@expo/steps": "
|
|
50
|
-
"@expo/template-file": "
|
|
51
|
-
"@expo/turtle-spawn": "
|
|
49
|
+
"@expo/steps": "22.1.0",
|
|
50
|
+
"@expo/template-file": "22.0.0",
|
|
51
|
+
"@expo/turtle-spawn": "22.0.0",
|
|
52
52
|
"@expo/xcpretty": "^4.3.1",
|
|
53
53
|
"@ngrok/ngrok": "1.7.0",
|
|
54
54
|
"@sentry/node": "7.77.0",
|
|
@@ -100,5 +100,5 @@
|
|
|
100
100
|
"typescript": "^5.5.4",
|
|
101
101
|
"uuid": "^9.0.1"
|
|
102
102
|
},
|
|
103
|
-
"gitHead": "
|
|
103
|
+
"gitHead": "5484dd607468c7711d915a2521df10531f8b9908"
|
|
104
104
|
}
|