@expo/build-tools 19.0.6 → 20.0.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/ios.js +4 -1
- package/dist/common/easBuildInternal.js +8 -0
- package/dist/context.d.ts +1 -3
- package/dist/context.js +0 -3
- package/dist/datadog.d.ts +1 -0
- package/dist/datadog.js +26 -3
- package/dist/ios/pod.js +4 -0
- package/dist/steps/functions/restoreBuildCache.js +5 -17
- package/dist/steps/functions/startAgentDeviceRemoteSession.js +13 -21
- package/dist/steps/functions/startArgentRemoteSession.js +13 -21
- package/dist/steps/functions/startServeSimRemoteSession.js +2 -2
- package/dist/steps/utils/ios/xcactivitylog.d.ts +6 -4
- package/dist/steps/utils/ios/xcactivitylog.js +41 -5
- package/dist/steps/utils/remoteDeviceRunSession.d.ts +10 -16
- package/dist/steps/utils/remoteDeviceRunSession.js +81 -65
- package/dist/templates/FastfileResign.d.ts +1 -1
- package/dist/templates/FastfileResign.js +1 -0
- package/dist/utils/IosSimulatorUtils.js +3 -1
- package/dist/utils/artifacts.js +1 -1
- package/package.json +9 -8
package/dist/builders/ios.js
CHANGED
|
@@ -166,13 +166,16 @@ async function buildAsync(ctx) {
|
|
|
166
166
|
}
|
|
167
167
|
try {
|
|
168
168
|
const { derivedDataPath, workspacePath } = (0, nullthrows_1.default)(fastlaneResult);
|
|
169
|
-
await (0, xcactivitylog_1.parseAndReportXcactivitylog)({
|
|
169
|
+
const { skipped } = await (0, xcactivitylog_1.parseAndReportXcactivitylog)({
|
|
170
170
|
derivedDataPath,
|
|
171
171
|
workspacePath,
|
|
172
172
|
logger: ctx.logger,
|
|
173
173
|
proxyBaseUrl: ctx.env.EAS_BUILD_COCOAPODS_CACHE_URL,
|
|
174
174
|
env: ctx.env,
|
|
175
175
|
});
|
|
176
|
+
if (skipped) {
|
|
177
|
+
ctx.markBuildPhaseSkipped();
|
|
178
|
+
}
|
|
176
179
|
}
|
|
177
180
|
catch (err) {
|
|
178
181
|
sentry_1.Sentry.capture('Failed to parse xcactivitylog', err);
|
|
@@ -28,6 +28,10 @@ async function runEasBuildInternalAsync({ job, logger, env, cwd, projectRootOver
|
|
|
28
28
|
else if (githubTriggerOptions?.autoSubmit) {
|
|
29
29
|
autoSubmitArgs.push('--auto-submit');
|
|
30
30
|
}
|
|
31
|
+
const refreshAdHocProvisioningProfileArgs = [];
|
|
32
|
+
if (job.platform === eas_build_job_1.Platform.IOS && job.refreshAdHocProvisioningProfile === true) {
|
|
33
|
+
refreshAdHocProvisioningProfileArgs.push('--refresh-ad-hoc-provisioning-profile');
|
|
34
|
+
}
|
|
31
35
|
try {
|
|
32
36
|
const result = await (0, turtle_spawn_1.default)(cmd, [
|
|
33
37
|
...args,
|
|
@@ -37,6 +41,7 @@ async function runEasBuildInternalAsync({ job, logger, env, cwd, projectRootOver
|
|
|
37
41
|
'--profile',
|
|
38
42
|
buildProfile,
|
|
39
43
|
...autoSubmitArgs,
|
|
44
|
+
...refreshAdHocProvisioningProfileArgs,
|
|
40
45
|
], {
|
|
41
46
|
cwd,
|
|
42
47
|
env: {
|
|
@@ -106,6 +111,9 @@ function validateEasBuildInternalResult({ oldJob, result, }) {
|
|
|
106
111
|
// We want to retain values that we have set on the job.
|
|
107
112
|
appId: oldJob.appId,
|
|
108
113
|
initiatingUserId: oldJob.initiatingUserId,
|
|
114
|
+
...(oldJob.platform === eas_build_job_1.Platform.IOS && oldJob.refreshAdHocProvisioningProfile === true
|
|
115
|
+
? { refreshAdHocProvisioningProfile: true }
|
|
116
|
+
: null),
|
|
109
117
|
});
|
|
110
118
|
(0, assert_1.default)(newJob.platform === oldJob.platform, 'eas-cli returned a job for a wrong platform');
|
|
111
119
|
const newMetadata = (0, eas_build_job_1.sanitizeMetadata)(value.metadata);
|
package/dist/context.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ExpoConfig } from '@expo/config';
|
|
2
|
-
import { BuildPhase,
|
|
2
|
+
import { BuildPhase, Env, GenericArtifactType, Job, ManagedArtifactType, Metadata } from '@expo/eas-build-job';
|
|
3
3
|
import { bunyan } from '@expo/logger';
|
|
4
4
|
import { Client } from '@urql/core';
|
|
5
5
|
import { PackageManager } from './utils/packageManager';
|
|
@@ -44,7 +44,6 @@ export interface BuildContextOptions {
|
|
|
44
44
|
tags?: Record<string, string>;
|
|
45
45
|
extras?: Record<string, string>;
|
|
46
46
|
}) => void;
|
|
47
|
-
reportBuildPhaseStats?: (stats: BuildPhaseStats) => void;
|
|
48
47
|
skipNativeBuild?: boolean;
|
|
49
48
|
metadata?: Metadata;
|
|
50
49
|
expoApiV2BaseUrl?: string;
|
|
@@ -73,7 +72,6 @@ export declare class BuildContext<TJob extends Job = Job> {
|
|
|
73
72
|
private buildPhaseSkipped;
|
|
74
73
|
private buildPhaseHasWarnings;
|
|
75
74
|
private _appConfig?;
|
|
76
|
-
private readonly reportBuildPhaseStats?;
|
|
77
75
|
readonly graphqlClient: Client;
|
|
78
76
|
constructor(job: TJob, options: BuildContextOptions);
|
|
79
77
|
get job(): TJob;
|
package/dist/context.js
CHANGED
|
@@ -36,7 +36,6 @@ class BuildContext {
|
|
|
36
36
|
buildPhaseSkipped = false;
|
|
37
37
|
buildPhaseHasWarnings = false;
|
|
38
38
|
_appConfig;
|
|
39
|
-
reportBuildPhaseStats;
|
|
40
39
|
graphqlClient;
|
|
41
40
|
constructor(job, options) {
|
|
42
41
|
this.workingdir = options.workingdir;
|
|
@@ -50,7 +49,6 @@ class BuildContext {
|
|
|
50
49
|
this._metadata = options.metadata;
|
|
51
50
|
this.skipNativeBuild = options.skipNativeBuild;
|
|
52
51
|
this.expoApiV2BaseUrl = options.expoApiV2BaseUrl;
|
|
53
|
-
this.reportBuildPhaseStats = options.reportBuildPhaseStats;
|
|
54
52
|
const environmentSecrets = this.getEnvironmentSecrets(job);
|
|
55
53
|
this._env = {
|
|
56
54
|
...options.env,
|
|
@@ -235,7 +233,6 @@ class BuildContext {
|
|
|
235
233
|
return;
|
|
236
234
|
}
|
|
237
235
|
await this.collectAndUpdateEnvVariablesAsync();
|
|
238
|
-
this.reportBuildPhaseStats?.({ buildPhase: this.buildPhase, result, durationMs });
|
|
239
236
|
if (this.job.platform) {
|
|
240
237
|
datadog_1.Datadog.distribution('eas.build.phase_duration', durationMs, {
|
|
241
238
|
build_phase: this.buildPhase.toLowerCase(),
|
package/dist/datadog.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ type DatadogSetupOptions = {
|
|
|
6
6
|
export declare const Datadog: {
|
|
7
7
|
setup(opts: DatadogSetupOptions | null): void;
|
|
8
8
|
distribution(name: string, value: number, tags?: Record<string, string>): void;
|
|
9
|
+
log(message: string, tags?: Record<string, string>): void;
|
|
9
10
|
flushAsync(): Promise<void>;
|
|
10
11
|
};
|
|
11
12
|
export {};
|
package/dist/datadog.js
CHANGED
|
@@ -4,7 +4,7 @@ exports.Datadog = void 0;
|
|
|
4
4
|
const sentry_1 = require("./sentry");
|
|
5
5
|
const turtleFetch_1 = require("./utils/turtleFetch");
|
|
6
6
|
let setupOptions = null;
|
|
7
|
-
let
|
|
7
|
+
let pendingUploads = [];
|
|
8
8
|
exports.Datadog = {
|
|
9
9
|
setup(opts) {
|
|
10
10
|
setupOptions = opts;
|
|
@@ -33,9 +33,32 @@ exports.Datadog = {
|
|
|
33
33
|
extras: { metrics },
|
|
34
34
|
});
|
|
35
35
|
});
|
|
36
|
-
|
|
36
|
+
pendingUploads.push(uploadPromise);
|
|
37
|
+
},
|
|
38
|
+
log(message, tags = {}) {
|
|
39
|
+
if (!setupOptions) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const { expoApiV2BaseUrl, turtleBuildId, robotAccessToken } = setupOptions;
|
|
43
|
+
const log = {
|
|
44
|
+
buildId: turtleBuildId,
|
|
45
|
+
message,
|
|
46
|
+
tags,
|
|
47
|
+
};
|
|
48
|
+
const uploadPromise = (0, turtleFetch_1.turtleFetch)(new URL('turtle-builds/logs', expoApiV2BaseUrl).toString(), 'POST', {
|
|
49
|
+
json: log,
|
|
50
|
+
headers: {
|
|
51
|
+
Authorization: `Bearer ${robotAccessToken}`,
|
|
52
|
+
},
|
|
53
|
+
shouldThrowOnNotOk: false,
|
|
54
|
+
}).catch(err => {
|
|
55
|
+
sentry_1.Sentry.capture('Failed to report turtle build log', err, {
|
|
56
|
+
extras: { log },
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
pendingUploads.push(uploadPromise);
|
|
37
60
|
},
|
|
38
61
|
async flushAsync() {
|
|
39
|
-
await Promise.allSettled(
|
|
62
|
+
await Promise.allSettled(pendingUploads);
|
|
40
63
|
},
|
|
41
64
|
};
|
package/dist/ios/pod.js
CHANGED
|
@@ -38,6 +38,10 @@ async function installPods(ctx, { infoCallbackFn }) {
|
|
|
38
38
|
};
|
|
39
39
|
}
|
|
40
40
|
async function resolvePrecompiledModulesPodInstallEnvAsync(ctx) {
|
|
41
|
+
if (ctx.env.EXPO_USE_PRECOMPILED_MODULES === '0') {
|
|
42
|
+
ctx.logger.info('EXPO_USE_PRECOMPILED_MODULES=0 is set; not enabling precompiled modules use.');
|
|
43
|
+
return {};
|
|
44
|
+
}
|
|
41
45
|
if (ctx.job.builderEnvironment?.env?.EAS_USE_PRECOMPILED_MODULES !== '1') {
|
|
42
46
|
return {};
|
|
43
47
|
}
|
|
@@ -18,6 +18,7 @@ const path_1 = __importDefault(require("path"));
|
|
|
18
18
|
const ccacheStats_1 = require("./ccacheStats");
|
|
19
19
|
const restoreCache_1 = require("./restoreCache");
|
|
20
20
|
const cacheKey_1 = require("../../utils/cacheKey");
|
|
21
|
+
const datadog_1 = require("../../datadog");
|
|
21
22
|
const gradleCacheKey_1 = require("../../utils/gradleCacheKey");
|
|
22
23
|
const turtleFetch_1 = require("../../utils/turtleFetch");
|
|
23
24
|
function createRestoreBuildCacheFunction() {
|
|
@@ -216,23 +217,10 @@ async function restoreGradleCacheAsync({ logger, workingDirectory, env, secrets,
|
|
|
216
217
|
});
|
|
217
218
|
const hitType = matchedKey === cacheKey ? 'direct_hit' : 'prefix_match';
|
|
218
219
|
logger.info(`Gradle cache restored to ${gradleCachesPath} (${hitType === 'direct_hit' ? 'direct hit' : 'prefix match'})`);
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
message: `Gradle cache restored (${hitType})`,
|
|
224
|
-
tags: {
|
|
225
|
-
event: 'gradle_cache_restored',
|
|
226
|
-
cache_hit_type: hitType,
|
|
227
|
-
},
|
|
228
|
-
},
|
|
229
|
-
headers: {
|
|
230
|
-
Authorization: `Bearer ${robotAccessToken}`,
|
|
231
|
-
},
|
|
232
|
-
shouldThrowOnNotOk: false,
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
catch { }
|
|
220
|
+
datadog_1.Datadog.log(`Gradle cache restored (${hitType})`, {
|
|
221
|
+
event: 'gradle_cache_restored',
|
|
222
|
+
cache_hit_type: hitType,
|
|
223
|
+
});
|
|
236
224
|
}
|
|
237
225
|
catch (err) {
|
|
238
226
|
if (err instanceof turtleFetch_1.TurtleFetchError && err.response?.status === 404) {
|
|
@@ -29,10 +29,13 @@ function createStartAgentDeviceRemoteSessionBuildFunction(ctx) {
|
|
|
29
29
|
}),
|
|
30
30
|
],
|
|
31
31
|
fn: async ({ logger, global }, { inputs, env }) => {
|
|
32
|
-
// Fail fast before any expensive setup if the
|
|
33
|
-
//
|
|
34
|
-
//
|
|
32
|
+
// Fail fast before any expensive setup if the injected env
|
|
33
|
+
// vars are missing: DEVICE_RUN_SESSION_ID (to report the remote config
|
|
34
|
+
// back to the API server), EAS_SIMULATOR_NGROK_TUNNEL_DOMAIN (base domain
|
|
35
|
+
// for our ngrok tunnels), and NGROK_AUTHTOKEN (to authenticate them).
|
|
35
36
|
const deviceRunSessionId = (0, remoteDeviceRunSession_1.getDeviceRunSessionIdOrThrow)(env);
|
|
37
|
+
const ngrokTunnelDomain = (0, remoteDeviceRunSession_1.getNgrokTunnelDomainOrThrow)(env);
|
|
38
|
+
const ngrokAuthtoken = (0, remoteDeviceRunSession_1.getNgrokAuthtokenOrThrow)(env);
|
|
36
39
|
const packageVersion = inputs.package_version.value;
|
|
37
40
|
const { runtimePlatform } = global;
|
|
38
41
|
logger.info(`Starting agent-device remote session (version: ${packageVersion ?? 'latest'}, runtime: ${runtimePlatform}).`);
|
|
@@ -40,12 +43,6 @@ function createStartAgentDeviceRemoteSessionBuildFunction(ctx) {
|
|
|
40
43
|
logger.info(`Selecting Xcode developer directory: ${XCODE_DEVELOPER_DIR}.`);
|
|
41
44
|
await (0, turtle_spawn_1.default)('sudo', ['xcode-select', '-s', XCODE_DEVELOPER_DIR], { env, logger });
|
|
42
45
|
}
|
|
43
|
-
logger.info('Ensuring cloudflared is installed.');
|
|
44
|
-
const cloudflaredCommand = await (0, remoteDeviceRunSession_1.ensureCloudflaredInstalledAsync)({
|
|
45
|
-
runtimePlatform,
|
|
46
|
-
env,
|
|
47
|
-
logger,
|
|
48
|
-
});
|
|
49
46
|
logger.info(packageVersion
|
|
50
47
|
? `Cloning agent-device @ v${packageVersion} into ${SRC_DIR}.`
|
|
51
48
|
: `Cloning agent-device (latest) into ${SRC_DIR}.`);
|
|
@@ -71,18 +68,12 @@ function createStartAgentDeviceRemoteSessionBuildFunction(ctx) {
|
|
|
71
68
|
parse: parseDaemonInfo,
|
|
72
69
|
});
|
|
73
70
|
logger.info(`Daemon is listening on port ${daemonPort}; loaded auth token.`);
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
logger.info('Waiting for a public tunnel URL.');
|
|
81
|
-
const agentDeviceRemoteSessionUrl = await (0, remoteDeviceRunSession_1.waitForMatchInOutputAsync)({
|
|
82
|
-
process: cloudflared,
|
|
83
|
-
pattern: /https:\/\/[a-z0-9-]+\.trycloudflare\.com/,
|
|
84
|
-
timeoutMs: STARTUP_TIMEOUT_MS,
|
|
85
|
-
description: 'cloudflared tunnel',
|
|
71
|
+
const agentDeviceRemoteSessionUrl = await (0, remoteDeviceRunSession_1.startNgrokTunnelAsync)({
|
|
72
|
+
port: daemonPort,
|
|
73
|
+
subdomainPrefix: 'agent-device',
|
|
74
|
+
baseDomain: ngrokTunnelDomain,
|
|
75
|
+
authtoken: ngrokAuthtoken,
|
|
76
|
+
logger,
|
|
86
77
|
});
|
|
87
78
|
logger.info(`Tunnel is ready at ${agentDeviceRemoteSessionUrl}.`);
|
|
88
79
|
// serve-sim is iOS-only — only launch it (and report a webPreviewUrl)
|
|
@@ -90,6 +81,7 @@ function createStartAgentDeviceRemoteSessionBuildFunction(ctx) {
|
|
|
90
81
|
let webPreviewUrl;
|
|
91
82
|
if (runtimePlatform === steps_1.BuildRuntimePlatform.DARWIN) {
|
|
92
83
|
const { previewUrl } = await (0, remoteDeviceRunSession_1.startServeSimWithTunnelAsync)({
|
|
84
|
+
baseDomain: ngrokTunnelDomain,
|
|
93
85
|
env,
|
|
94
86
|
logger,
|
|
95
87
|
timeoutMs: STARTUP_TIMEOUT_MS,
|
|
@@ -31,10 +31,13 @@ function createStartArgentRemoteSessionBuildFunction(ctx) {
|
|
|
31
31
|
}),
|
|
32
32
|
],
|
|
33
33
|
fn: async ({ logger, global }, { inputs, env }) => {
|
|
34
|
-
// Fail fast before any expensive setup if the
|
|
35
|
-
//
|
|
36
|
-
//
|
|
34
|
+
// Fail fast before any expensive setup if the injected env
|
|
35
|
+
// vars are missing: DEVICE_RUN_SESSION_ID (to report the remote config
|
|
36
|
+
// back to the API server), EAS_SIMULATOR_NGROK_TUNNEL_DOMAIN (base domain
|
|
37
|
+
// for our ngrok tunnels), and NGROK_AUTHTOKEN (to authenticate them).
|
|
37
38
|
const deviceRunSessionId = (0, remoteDeviceRunSession_1.getDeviceRunSessionIdOrThrow)(env);
|
|
39
|
+
const ngrokTunnelDomain = (0, remoteDeviceRunSession_1.getNgrokTunnelDomainOrThrow)(env);
|
|
40
|
+
const ngrokAuthtoken = (0, remoteDeviceRunSession_1.getNgrokAuthtokenOrThrow)(env);
|
|
38
41
|
const packageVersion = inputs.package_version.value;
|
|
39
42
|
const versionSpec = packageVersion ?? 'latest';
|
|
40
43
|
const { runtimePlatform } = global;
|
|
@@ -43,12 +46,6 @@ function createStartArgentRemoteSessionBuildFunction(ctx) {
|
|
|
43
46
|
logger.info(`Selecting Xcode developer directory: ${XCODE_DEVELOPER_DIR}.`);
|
|
44
47
|
await (0, turtle_spawn_1.default)('sudo', ['xcode-select', '-s', XCODE_DEVELOPER_DIR], { env, logger });
|
|
45
48
|
}
|
|
46
|
-
logger.info('Ensuring cloudflared is installed.');
|
|
47
|
-
const cloudflaredCommand = await (0, remoteDeviceRunSession_1.ensureCloudflaredInstalledAsync)({
|
|
48
|
-
runtimePlatform,
|
|
49
|
-
env,
|
|
50
|
-
logger,
|
|
51
|
-
});
|
|
52
49
|
// Stale state from a previous run would mask the new server's port.
|
|
53
50
|
await node_fs_1.default.promises.rm(ARGENT_STATE_FILE, { force: true });
|
|
54
51
|
logger.info(`Launching ${ARGENT_PACKAGE_NAME}@${versionSpec} via bunx.`);
|
|
@@ -69,24 +66,19 @@ function createStartArgentRemoteSessionBuildFunction(ctx) {
|
|
|
69
66
|
parse: parseArgentToolServerState,
|
|
70
67
|
});
|
|
71
68
|
logger.info(`Argent tool-server is listening on port ${toolServerPort}.`);
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
logger.info('Waiting for a public tunnel URL.');
|
|
79
|
-
const toolsUrl = await (0, remoteDeviceRunSession_1.waitForMatchInOutputAsync)({
|
|
80
|
-
process: cloudflared,
|
|
81
|
-
pattern: /https:\/\/[a-z0-9-]+\.trycloudflare\.com/,
|
|
82
|
-
timeoutMs: STARTUP_TIMEOUT_MS,
|
|
83
|
-
description: 'cloudflared tunnel',
|
|
69
|
+
const toolsUrl = await (0, remoteDeviceRunSession_1.startNgrokTunnelAsync)({
|
|
70
|
+
port: toolServerPort,
|
|
71
|
+
subdomainPrefix: 'argent',
|
|
72
|
+
baseDomain: ngrokTunnelDomain,
|
|
73
|
+
authtoken: ngrokAuthtoken,
|
|
74
|
+
logger,
|
|
84
75
|
});
|
|
85
76
|
logger.info(`Tunnel is ready at ${toolsUrl}.`);
|
|
86
77
|
// serve-sim is iOS-only — Android sessions go without a preview URL.
|
|
87
78
|
let webPreviewUrl;
|
|
88
79
|
if (runtimePlatform === steps_1.BuildRuntimePlatform.DARWIN) {
|
|
89
80
|
const serveSim = await (0, remoteDeviceRunSession_1.startServeSimWithTunnelAsync)({
|
|
81
|
+
baseDomain: ngrokTunnelDomain,
|
|
90
82
|
env,
|
|
91
83
|
logger,
|
|
92
84
|
timeoutMs: STARTUP_TIMEOUT_MS,
|
|
@@ -18,12 +18,12 @@ function createStartServeSimRemoteSessionBuildFunction(ctx) {
|
|
|
18
18
|
supportedRuntimePlatforms: [steps_1.BuildRuntimePlatform.DARWIN],
|
|
19
19
|
fn: async ({ logger }, { env }) => {
|
|
20
20
|
const deviceRunSessionId = (0, remoteDeviceRunSession_1.getDeviceRunSessionIdOrThrow)(env);
|
|
21
|
+
const ngrokTunnelDomain = (0, remoteDeviceRunSession_1.getNgrokTunnelDomainOrThrow)(env);
|
|
21
22
|
logger.info('Starting serve-sim remote session.');
|
|
22
23
|
logger.info(`Selecting Xcode developer directory: ${XCODE_DEVELOPER_DIR}.`);
|
|
23
24
|
await (0, turtle_spawn_1.default)('sudo', ['xcode-select', '-s', XCODE_DEVELOPER_DIR], { env, logger });
|
|
24
|
-
logger.info('Ensuring cloudflared is installed.');
|
|
25
|
-
await (0, remoteDeviceRunSession_1.ensureBrewPackageInstalledAsync)({ name: 'cloudflared', env, logger });
|
|
26
25
|
const { previewUrl, streamUrl } = await (0, remoteDeviceRunSession_1.startServeSimWithTunnelAsync)({
|
|
26
|
+
baseDomain: ngrokTunnelDomain,
|
|
27
27
|
env,
|
|
28
28
|
logger,
|
|
29
29
|
timeoutMs: STARTUP_TIMEOUT_MS,
|
|
@@ -2,9 +2,9 @@ import { bunyan } from '@expo/logger';
|
|
|
2
2
|
import { BuildStepEnv } from '@expo/steps';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* Catches all internal failures (logged + routed to Sentry); returns
|
|
6
|
+
* `{ skipped: true }` when analysis did not produce a report so callers can
|
|
7
|
+
* mark the build phase skipped.
|
|
8
8
|
*/
|
|
9
9
|
export declare function parseAndReportXcactivitylog({ derivedDataPath, workspacePath, xclogparserVersion, logger, proxyBaseUrl, env, }: {
|
|
10
10
|
derivedDataPath: string;
|
|
@@ -13,7 +13,9 @@ export declare function parseAndReportXcactivitylog({ derivedDataPath, workspace
|
|
|
13
13
|
logger: bunyan;
|
|
14
14
|
proxyBaseUrl?: string;
|
|
15
15
|
env: BuildStepEnv;
|
|
16
|
-
}): Promise<
|
|
16
|
+
}): Promise<{
|
|
17
|
+
skipped: boolean;
|
|
18
|
+
}>;
|
|
17
19
|
declare const XcactivitylogStepSchemaZ: z.ZodObject<{
|
|
18
20
|
title: z.ZodOptional<z.ZodString>;
|
|
19
21
|
detailStepType: z.ZodOptional<z.ZodString>;
|
|
@@ -21,14 +21,40 @@ const XCLOGPARSER_DOWNLOAD_URL = 'https://storage.googleapis.com/turtle-v2/xclog
|
|
|
21
21
|
const XCLOGPARSER_DOWNLOAD_TIMEOUT_MS = 20_000;
|
|
22
22
|
const XCLOGPARSER_OUTPUT_FILENAME = 'xcactivitylog.json';
|
|
23
23
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
24
|
+
* Catches all internal failures (logged + routed to Sentry); returns
|
|
25
|
+
* `{ skipped: true }` when analysis did not produce a report so callers can
|
|
26
|
+
* mark the build phase skipped.
|
|
27
27
|
*/
|
|
28
28
|
async function parseAndReportXcactivitylog({ derivedDataPath, workspacePath, xclogparserVersion, logger, proxyBaseUrl, env, }) {
|
|
29
29
|
let tempDir;
|
|
30
|
-
let phase = '
|
|
30
|
+
let phase = 'checking_xcactivitylog_existence';
|
|
31
31
|
try {
|
|
32
|
+
const logsBuildDir = path_1.default.join(derivedDataPath, 'Logs', 'Build');
|
|
33
|
+
let buildLogEntries;
|
|
34
|
+
try {
|
|
35
|
+
buildLogEntries = await fs_extra_1.default.readdir(logsBuildDir);
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
if (err?.code !== 'ENOENT') {
|
|
39
|
+
throw err;
|
|
40
|
+
}
|
|
41
|
+
buildLogEntries = [];
|
|
42
|
+
}
|
|
43
|
+
const hasActivityLog = buildLogEntries.some(entry => entry.endsWith('.xcactivitylog'));
|
|
44
|
+
if (!hasActivityLog) {
|
|
45
|
+
logger.info([
|
|
46
|
+
`Build performance analysis skipped: no .xcactivitylog files found at ${logsBuildDir}.`,
|
|
47
|
+
'',
|
|
48
|
+
'This typically happens when your project has a custom ios/Gymfile. To enable',
|
|
49
|
+
'build performance analysis, add the following lines to your Gymfile:',
|
|
50
|
+
'',
|
|
51
|
+
' derived_data_path("./build")',
|
|
52
|
+
' result_bundle(true)',
|
|
53
|
+
' result_bundle_path("./build/result-bundle.xcresult")',
|
|
54
|
+
].join('\n'));
|
|
55
|
+
return { skipped: true };
|
|
56
|
+
}
|
|
57
|
+
phase = 'creating_temp_directory';
|
|
32
58
|
tempDir = await fs_extra_1.default.mkdtemp(path_1.default.join(os_1.default.tmpdir(), 'xclogparser-'));
|
|
33
59
|
phase = 'resolving_xclogparser';
|
|
34
60
|
const preinstalledVersion = await detectPreinstalledXclogparserVersion(env);
|
|
@@ -63,11 +89,21 @@ async function parseAndReportXcactivitylog({ derivedDataPath, workspacePath, xcl
|
|
|
63
89
|
phase = 'parsing_xclogparser_output';
|
|
64
90
|
const data = XcactivitylogDataSchemaZ.parse(JSON.parse(await fs_extra_1.default.readFile(jsonOutputPath, 'utf8')));
|
|
65
91
|
logger.info(formatReport(data));
|
|
92
|
+
return { skipped: false };
|
|
66
93
|
}
|
|
67
94
|
catch (err) {
|
|
68
95
|
logger.info('Build performance analysis skipped.');
|
|
69
96
|
const msg = `Build performance analysis failed during "${phase}"`;
|
|
70
|
-
sentry_1.Sentry.capture(msg, err, {
|
|
97
|
+
sentry_1.Sentry.capture(msg, err, {
|
|
98
|
+
tags: { phase },
|
|
99
|
+
extras: {
|
|
100
|
+
exitStatus: err?.status,
|
|
101
|
+
signal: err?.signal,
|
|
102
|
+
stderr: err?.stderr?.slice(-4000),
|
|
103
|
+
stdout: err?.stdout?.slice(-4000),
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
return { skipped: true };
|
|
71
107
|
}
|
|
72
108
|
finally {
|
|
73
109
|
if (tempDir) {
|
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
import { bunyan } from '@expo/logger';
|
|
2
|
-
import {
|
|
2
|
+
import { BuildStepEnv } from '@expo/steps';
|
|
3
3
|
import { CustomBuildContext } from '../../customBuildContext';
|
|
4
4
|
export declare function getDeviceRunSessionIdOrThrow(env: BuildStepEnv): string;
|
|
5
|
+
export declare function getNgrokTunnelDomainOrThrow(env: BuildStepEnv): string;
|
|
6
|
+
export declare function getNgrokAuthtokenOrThrow(env: BuildStepEnv): string;
|
|
5
7
|
export declare function uploadRemoteSessionConfigAsync({ ctx, deviceRunSessionId, remoteConfig, logger, }: {
|
|
6
8
|
ctx: CustomBuildContext;
|
|
7
9
|
deviceRunSessionId: string;
|
|
8
10
|
remoteConfig: Record<string, unknown>;
|
|
9
11
|
logger: bunyan;
|
|
10
12
|
}): Promise<void>;
|
|
11
|
-
export declare function ensureBrewPackageInstalledAsync({ name, env, logger, }: {
|
|
12
|
-
name: string;
|
|
13
|
-
env: BuildStepEnv;
|
|
14
|
-
logger: bunyan;
|
|
15
|
-
}): Promise<void>;
|
|
16
13
|
export type DetachedProcessHandle = {
|
|
17
14
|
getOutput: () => string;
|
|
18
15
|
};
|
|
@@ -22,7 +19,8 @@ export declare function spawnDetached({ command, args, cwd, env, }: {
|
|
|
22
19
|
cwd?: string;
|
|
23
20
|
env: BuildStepEnv;
|
|
24
21
|
}): DetachedProcessHandle;
|
|
25
|
-
export declare function startServeSimWithTunnelAsync({ env, logger, timeoutMs, }: {
|
|
22
|
+
export declare function startServeSimWithTunnelAsync({ baseDomain, env, logger, timeoutMs, }: {
|
|
23
|
+
baseDomain: string;
|
|
26
24
|
env: BuildStepEnv;
|
|
27
25
|
logger: bunyan;
|
|
28
26
|
timeoutMs: number;
|
|
@@ -30,17 +28,13 @@ export declare function startServeSimWithTunnelAsync({ env, logger, timeoutMs, }
|
|
|
30
28
|
previewUrl: string;
|
|
31
29
|
streamUrl: string;
|
|
32
30
|
}>;
|
|
33
|
-
export declare function
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
export declare function startNgrokTunnelAsync({ port, subdomainPrefix, baseDomain, authtoken, logger, }: {
|
|
32
|
+
port: number;
|
|
33
|
+
subdomainPrefix: string;
|
|
34
|
+
baseDomain: string;
|
|
35
|
+
authtoken: string;
|
|
36
36
|
logger: bunyan;
|
|
37
37
|
}): Promise<string>;
|
|
38
|
-
export declare function waitForMatchInOutputAsync({ process, pattern, timeoutMs, description, }: {
|
|
39
|
-
process: DetachedProcessHandle;
|
|
40
|
-
pattern: RegExp;
|
|
41
|
-
timeoutMs: number;
|
|
42
|
-
description: string;
|
|
43
|
-
}): Promise<string>;
|
|
44
38
|
export declare function waitForFileAsync<T>({ filePath, timeoutMs, description, parse, }: {
|
|
45
39
|
filePath: string;
|
|
46
40
|
timeoutMs: number;
|
|
@@ -1,25 +1,56 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
37
|
};
|
|
5
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
39
|
exports.getDeviceRunSessionIdOrThrow = getDeviceRunSessionIdOrThrow;
|
|
40
|
+
exports.getNgrokTunnelDomainOrThrow = getNgrokTunnelDomainOrThrow;
|
|
41
|
+
exports.getNgrokAuthtokenOrThrow = getNgrokAuthtokenOrThrow;
|
|
7
42
|
exports.uploadRemoteSessionConfigAsync = uploadRemoteSessionConfigAsync;
|
|
8
|
-
exports.ensureBrewPackageInstalledAsync = ensureBrewPackageInstalledAsync;
|
|
9
43
|
exports.spawnDetached = spawnDetached;
|
|
10
44
|
exports.startServeSimWithTunnelAsync = startServeSimWithTunnelAsync;
|
|
11
|
-
exports.
|
|
12
|
-
exports.waitForMatchInOutputAsync = waitForMatchInOutputAsync;
|
|
45
|
+
exports.startNgrokTunnelAsync = startNgrokTunnelAsync;
|
|
13
46
|
exports.waitForFileAsync = waitForFileAsync;
|
|
14
47
|
const eas_build_job_1 = require("@expo/eas-build-job");
|
|
15
|
-
const steps_1 = require("@expo/steps");
|
|
16
48
|
const turtle_spawn_1 = __importDefault(require("@expo/turtle-spawn"));
|
|
49
|
+
const ngrok = __importStar(require("@ngrok/ngrok"));
|
|
17
50
|
const gql_tada_1 = require("gql.tada");
|
|
51
|
+
const node_crypto_1 = require("node:crypto");
|
|
18
52
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
19
|
-
const node_os_1 = __importDefault(require("node:os"));
|
|
20
53
|
const retry_1 = require("../../utils/retry");
|
|
21
|
-
const TRYCLOUDFLARE_URL_PATTERN = /https:\/\/[a-z0-9-]+\.trycloudflare\.com/;
|
|
22
|
-
const CLOUDFLARED_LINUX_INSTALL_PATH = '/usr/local/bin/cloudflared';
|
|
23
54
|
const START_DEVICE_RUN_SESSION_MUTATION = (0, gql_tada_1.graphql)(`
|
|
24
55
|
mutation StartDeviceRunSession($deviceRunSessionId: ID!, $remoteConfig: JSONObject!) {
|
|
25
56
|
deviceRunSession {
|
|
@@ -37,11 +68,29 @@ function getDeviceRunSessionIdOrThrow(env) {
|
|
|
37
68
|
const deviceRunSessionId = env.DEVICE_RUN_SESSION_ID;
|
|
38
69
|
if (!deviceRunSessionId) {
|
|
39
70
|
throw new eas_build_job_1.SystemError('DEVICE_RUN_SESSION_ID is not set. ' +
|
|
40
|
-
'This step must run as part of a device run session
|
|
71
|
+
'This step must run as part of a device run session ' +
|
|
41
72
|
'which injects DEVICE_RUN_SESSION_ID into the job environment.');
|
|
42
73
|
}
|
|
43
74
|
return deviceRunSessionId;
|
|
44
75
|
}
|
|
76
|
+
function getNgrokTunnelDomainOrThrow(env) {
|
|
77
|
+
const baseDomain = env.EAS_SIMULATOR_NGROK_TUNNEL_DOMAIN;
|
|
78
|
+
if (!baseDomain) {
|
|
79
|
+
throw new eas_build_job_1.SystemError('EAS_SIMULATOR_NGROK_TUNNEL_DOMAIN is not set. ' +
|
|
80
|
+
'This step must run as part of a device run session ' +
|
|
81
|
+
'which injects EAS_SIMULATOR_NGROK_TUNNEL_DOMAIN into the job environment.');
|
|
82
|
+
}
|
|
83
|
+
return baseDomain;
|
|
84
|
+
}
|
|
85
|
+
function getNgrokAuthtokenOrThrow(env) {
|
|
86
|
+
const authtoken = env.NGROK_AUTHTOKEN;
|
|
87
|
+
if (!authtoken) {
|
|
88
|
+
throw new eas_build_job_1.SystemError('NGROK_AUTHTOKEN is not set. ' +
|
|
89
|
+
'This step must run as part of a device run session ' +
|
|
90
|
+
'which injects NGROK_AUTHTOKEN into the job environment.');
|
|
91
|
+
}
|
|
92
|
+
return authtoken;
|
|
93
|
+
}
|
|
45
94
|
async function uploadRemoteSessionConfigAsync({ ctx, deviceRunSessionId, remoteConfig, logger, }) {
|
|
46
95
|
logger.info(`Reporting remote config to the API server (device run session: ${deviceRunSessionId}).`);
|
|
47
96
|
const result = await ctx.graphqlClient
|
|
@@ -51,9 +100,6 @@ async function uploadRemoteSessionConfigAsync({ ctx, deviceRunSessionId, remoteC
|
|
|
51
100
|
throw new eas_build_job_1.SystemError(`Failed to start device run session ${deviceRunSessionId}: ${result.error.message}`);
|
|
52
101
|
}
|
|
53
102
|
}
|
|
54
|
-
async function ensureBrewPackageInstalledAsync({ name, env, logger, }) {
|
|
55
|
-
await (0, turtle_spawn_1.default)('bash', ['-c', `command -v ${name} >/dev/null 2>&1 || HOMEBREW_NO_AUTO_UPDATE=1 brew install ${name}`], { env, logger });
|
|
56
|
-
}
|
|
57
103
|
function spawnDetached({ command, args, cwd, env, }) {
|
|
58
104
|
const promise = (0, turtle_spawn_1.default)(command, args, {
|
|
59
105
|
cwd,
|
|
@@ -73,19 +119,23 @@ function spawnDetached({ command, args, cwd, env, }) {
|
|
|
73
119
|
promise.child.stderr?.on('data', appendChunk);
|
|
74
120
|
return { getOutput: () => output };
|
|
75
121
|
}
|
|
76
|
-
async function startServeSimWithTunnelAsync({ env, logger, timeoutMs, }) {
|
|
122
|
+
async function startServeSimWithTunnelAsync({ baseDomain, env, logger, timeoutMs, }) {
|
|
77
123
|
logger.info('Launching serve-sim with tunnel.');
|
|
78
124
|
const serveSim = spawnDetached({
|
|
79
125
|
command: 'npx',
|
|
80
126
|
args: [
|
|
81
127
|
'serve-sim-szdziedzic@latest',
|
|
82
128
|
'--tunnel',
|
|
83
|
-
'--tunnel-
|
|
84
|
-
'
|
|
129
|
+
'--tunnel-provider',
|
|
130
|
+
'ngrok',
|
|
131
|
+
'--tunnel-domain',
|
|
132
|
+
baseDomain,
|
|
85
133
|
'--stream-max-dimension',
|
|
86
134
|
'1280',
|
|
87
135
|
'--stream-quality',
|
|
88
136
|
'0.55',
|
|
137
|
+
'--codec',
|
|
138
|
+
'h264',
|
|
89
139
|
],
|
|
90
140
|
env,
|
|
91
141
|
});
|
|
@@ -93,8 +143,8 @@ async function startServeSimWithTunnelAsync({ env, logger, timeoutMs, }) {
|
|
|
93
143
|
const deadline = Date.now() + timeoutMs;
|
|
94
144
|
while (Date.now() < deadline) {
|
|
95
145
|
const output = serveSim.getOutput();
|
|
96
|
-
const previewUrl = matchLabeledUrl(output, 'Tunnel');
|
|
97
|
-
const streamUrl = matchLabeledUrl(output, 'Stream');
|
|
146
|
+
const previewUrl = matchLabeledUrl({ output, label: 'Tunnel', baseDomain });
|
|
147
|
+
const streamUrl = matchLabeledUrl({ output, label: 'Stream', baseDomain });
|
|
98
148
|
if (previewUrl && streamUrl) {
|
|
99
149
|
return { previewUrl, streamUrl };
|
|
100
150
|
}
|
|
@@ -102,59 +152,25 @@ async function startServeSimWithTunnelAsync({ env, logger, timeoutMs, }) {
|
|
|
102
152
|
}
|
|
103
153
|
throw new eas_build_job_1.SystemError(`Timed out waiting for serve-sim to report Tunnel and Stream URLs. Last output:\n${serveSim.getOutput() || '<empty>'}`);
|
|
104
154
|
}
|
|
105
|
-
function matchLabeledUrl(
|
|
106
|
-
const labelPattern = new RegExp(`${label}:\\s*(
|
|
107
|
-
const match = labelPattern.exec(
|
|
155
|
+
function matchLabeledUrl({ output, label, baseDomain, }) {
|
|
156
|
+
const labelPattern = new RegExp(`${label}:\\s*(https:\\/\\/[a-z0-9-]+\\.${escapeRegExp(baseDomain)})`);
|
|
157
|
+
const match = labelPattern.exec(output);
|
|
108
158
|
return match ? match[1] : null;
|
|
109
159
|
}
|
|
110
|
-
async function
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
const downloadUrl = `https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-${cloudflaredArch}`;
|
|
120
|
-
logger.info(`Downloading cloudflared from ${downloadUrl} to ${CLOUDFLARED_LINUX_INSTALL_PATH}.`);
|
|
121
|
-
await (0, turtle_spawn_1.default)('sudo', ['curl', '-fsSL', '-o', CLOUDFLARED_LINUX_INSTALL_PATH, downloadUrl], {
|
|
122
|
-
env,
|
|
123
|
-
logger,
|
|
124
|
-
});
|
|
125
|
-
await (0, turtle_spawn_1.default)('sudo', ['chmod', '+x', CLOUDFLARED_LINUX_INSTALL_PATH], { env, logger });
|
|
126
|
-
// Return the absolute install path so the tunnel command works even when
|
|
127
|
-
// /usr/local/bin is not on the step's PATH.
|
|
128
|
-
return CLOUDFLARED_LINUX_INSTALL_PATH;
|
|
129
|
-
}
|
|
130
|
-
function cloudflaredLinuxArchForNodeArch(arch) {
|
|
131
|
-
if (arch === 'x64') {
|
|
132
|
-
return 'amd64';
|
|
133
|
-
}
|
|
134
|
-
if (arch === 'arm64') {
|
|
135
|
-
return 'arm64';
|
|
136
|
-
}
|
|
137
|
-
throw new eas_build_job_1.SystemError(`Unsupported architecture for cloudflared on Linux: "${arch}". Expected "x64" or "arm64".`);
|
|
138
|
-
}
|
|
139
|
-
async function isCommandAvailableAsync({ command, env, }) {
|
|
140
|
-
try {
|
|
141
|
-
await (0, turtle_spawn_1.default)('bash', ['-c', `command -v ${command}`], { env, ignoreStdio: true });
|
|
142
|
-
return true;
|
|
143
|
-
}
|
|
144
|
-
catch {
|
|
145
|
-
return false;
|
|
160
|
+
async function startNgrokTunnelAsync({ port, subdomainPrefix, baseDomain, authtoken, logger, }) {
|
|
161
|
+
const domain = `${subdomainPrefix}-${(0, node_crypto_1.randomBytes)(8).toString('hex')}.${baseDomain}`;
|
|
162
|
+
logger.info(`Starting ngrok tunnel ${domain} -> http://localhost:${port}.`);
|
|
163
|
+
// Run the ngrok agent in-process via the SDK; it keeps the session alive until
|
|
164
|
+
// the process exits, and the step blocks forever to hold it open.
|
|
165
|
+
const listener = await ngrok.forward({ addr: port, authtoken, domain });
|
|
166
|
+
const url = listener.url();
|
|
167
|
+
if (!url) {
|
|
168
|
+
throw new eas_build_job_1.SystemError(`ngrok tunnel for ${domain} did not return a public URL.`);
|
|
146
169
|
}
|
|
170
|
+
return url;
|
|
147
171
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
while (Date.now() < deadline) {
|
|
151
|
-
const match = pattern.exec(process.getOutput());
|
|
152
|
-
if (match) {
|
|
153
|
-
return match[1] ?? match[0];
|
|
154
|
-
}
|
|
155
|
-
await (0, retry_1.sleepAsync)(1_000);
|
|
156
|
-
}
|
|
157
|
-
throw new eas_build_job_1.SystemError(`Timed out waiting for ${description} to start. Last output:\n${process.getOutput() || '<empty>'}`);
|
|
172
|
+
function escapeRegExp(value) {
|
|
173
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
158
174
|
}
|
|
159
175
|
async function waitForFileAsync({ filePath, timeoutMs, description, parse, }) {
|
|
160
176
|
const deadline = Date.now() + timeoutMs;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const FastfileResignTemplate = "lane :do_resign do\n resign(\n ipa: \"<%- IPA_PATH %>\",\n signing_identity: \"<%- SIGNING_IDENTITY %>\",\n provisioning_profile: {<% _.forEach(PROFILES, function(profile) { %>\n \"<%- profile.BUNDLE_ID %>\" => \"<%- profile.PATH %>\",<% }); %>\n },\n keychain_path: \"<%- KEYCHAIN_PATH %>\"\n )\nend\n";
|
|
1
|
+
export declare const FastfileResignTemplate = "lane :do_resign do\n resign(\n ipa: \"<%- IPA_PATH %>\",\n signing_identity: \"<%- SIGNING_IDENTITY %>\",\n provisioning_profile: {<% _.forEach(PROFILES, function(profile) { %>\n \"<%- profile.BUNDLE_ID %>\" => \"<%- profile.PATH %>\",<% }); %>\n },\n use_app_entitlements: true,\n keychain_path: \"<%- KEYCHAIN_PATH %>\"\n )\nend\n";
|
|
@@ -8,6 +8,7 @@ exports.FastfileResignTemplate = `lane :do_resign do
|
|
|
8
8
|
provisioning_profile: {<% _.forEach(PROFILES, function(profile) { %>
|
|
9
9
|
"<%- profile.BUNDLE_ID %>" => "<%- profile.PATH %>",<% }); %>
|
|
10
10
|
},
|
|
11
|
+
use_app_entitlements: true,
|
|
11
12
|
keychain_path: "<%- KEYCHAIN_PATH %>"
|
|
12
13
|
)
|
|
13
14
|
end
|
|
@@ -49,8 +49,9 @@ var IosSimulatorUtils;
|
|
|
49
49
|
}
|
|
50
50
|
IosSimulatorUtils.startAsync = startAsync;
|
|
51
51
|
async function waitForReadyAsync({ udid, env, }) {
|
|
52
|
+
const readinessScreenshotPath = node_path_1.default.join(node_os_1.default.tmpdir(), 'eas-simulator-readiness.png');
|
|
52
53
|
await (0, retry_1.retryAsync)(async () => {
|
|
53
|
-
await (0, turtle_spawn_1.default)('xcrun', ['simctl', 'io', udid, 'screenshot',
|
|
54
|
+
await (0, turtle_spawn_1.default)('xcrun', ['simctl', 'io', udid, 'screenshot', readinessScreenshotPath], {
|
|
54
55
|
env,
|
|
55
56
|
});
|
|
56
57
|
}, {
|
|
@@ -60,6 +61,7 @@ var IosSimulatorUtils;
|
|
|
60
61
|
retryIntervalMs: 1_000,
|
|
61
62
|
},
|
|
62
63
|
});
|
|
64
|
+
await node_fs_1.default.promises.rm(readinessScreenshotPath, { force: true });
|
|
63
65
|
// Wait for data migration to complete before declaring the simulator ready
|
|
64
66
|
// Based on WebKit's approach: https://trac.webkit.org/changeset/231452/webkit
|
|
65
67
|
await (0, retry_1.retryAsync)(async () => {
|
package/dist/utils/artifacts.js
CHANGED
|
@@ -17,7 +17,7 @@ class FindArtifactsError extends Error {
|
|
|
17
17
|
}
|
|
18
18
|
exports.FindArtifactsError = FindArtifactsError;
|
|
19
19
|
async function findArtifacts({ rootDir, patternOrPath, logger, }) {
|
|
20
|
-
const files = path_1.default.isAbsolute(patternOrPath)
|
|
20
|
+
const files = path_1.default.isAbsolute(patternOrPath) && !fast_glob_1.default.isDynamicPattern(patternOrPath)
|
|
21
21
|
? (await fs_extra_1.default.pathExists(patternOrPath))
|
|
22
22
|
? [patternOrPath]
|
|
23
23
|
: []
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@expo/build-tools",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "20.0.0",
|
|
4
4
|
"bugs": "https://github.com/expo/eas-cli/issues",
|
|
5
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"author": "Expo <support@expo.io>",
|
|
@@ -37,19 +37,20 @@
|
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@expo/config": "55.0.10",
|
|
39
39
|
"@expo/config-plugins": "55.0.7",
|
|
40
|
-
"@expo/downloader": "
|
|
41
|
-
"@expo/eas-build-job": "
|
|
40
|
+
"@expo/downloader": "20.0.0",
|
|
41
|
+
"@expo/eas-build-job": "20.0.0",
|
|
42
42
|
"@expo/env": "^0.4.0",
|
|
43
|
-
"@expo/logger": "
|
|
43
|
+
"@expo/logger": "20.0.0",
|
|
44
44
|
"@expo/package-manager": "1.9.10",
|
|
45
45
|
"@expo/plist": "^0.2.0",
|
|
46
46
|
"@expo/results": "^1.0.0",
|
|
47
47
|
"@expo/spawn-async": "1.7.2",
|
|
48
|
-
"@expo/steps": "
|
|
49
|
-
"@expo/template-file": "
|
|
50
|
-
"@expo/turtle-spawn": "
|
|
48
|
+
"@expo/steps": "20.0.0",
|
|
49
|
+
"@expo/template-file": "20.0.0",
|
|
50
|
+
"@expo/turtle-spawn": "20.0.0",
|
|
51
51
|
"@expo/xcpretty": "^4.3.1",
|
|
52
52
|
"@google-cloud/storage": "^7.11.2",
|
|
53
|
+
"@ngrok/ngrok": "1.7.0",
|
|
53
54
|
"@sentry/node": "7.77.0",
|
|
54
55
|
"@urql/core": "^6.0.1",
|
|
55
56
|
"bplist-parser": "0.3.2",
|
|
@@ -99,5 +100,5 @@
|
|
|
99
100
|
"typescript": "^5.5.4",
|
|
100
101
|
"uuid": "^9.0.1"
|
|
101
102
|
},
|
|
102
|
-
"gitHead": "
|
|
103
|
+
"gitHead": "890387b3b62c2ed2a946ec0e1197ff69f3e29342"
|
|
103
104
|
}
|