@expo/build-tools 20.4.0 → 20.5.1

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.
@@ -169,7 +169,7 @@ async function uploadProjectMetadataAsync(ctx, { projectDirectory }) {
169
169
  }
170
170
  }
171
171
  `), {
172
- buildId: ctx.env.EAS_BUILD_ID,
172
+ buildId: (0, nullthrows_1.default)(ctx.env.EAS_BUILD_ID, 'EAS_BUILD_ID is not set'),
173
173
  projectMetadataFile: {
174
174
  type: 'GCS',
175
175
  bucketKey: uploadSession.bucketKey,
package/dist/context.d.ts CHANGED
@@ -43,7 +43,7 @@ export interface BuildContextOptions {
43
43
  }>;
44
44
  reportError?: (msg: string, err?: Error, options?: {
45
45
  tags?: Record<string, string>;
46
- extras?: Record<string, string>;
46
+ extras?: Record<string, string | undefined>;
47
47
  }) => void;
48
48
  skipNativeBuild?: boolean;
49
49
  metadata?: Metadata;
@@ -58,7 +58,7 @@ export declare class BuildContext<TJob extends Job = Job> {
58
58
  readonly cacheManager?: CacheManager;
59
59
  readonly reportError?: (msg: string, err?: Error, options?: {
60
60
  tags?: Record<string, string>;
61
- extras?: Record<string, string>;
61
+ extras?: Record<string, string | undefined>;
62
62
  }) => void;
63
63
  readonly skipNativeBuild?: boolean;
64
64
  readonly expoApiV2BaseUrl?: string;
@@ -19,6 +19,6 @@ export declare function runFastlaneResign<TJob extends Ios.Job>(ctx: BuildContex
19
19
  }): Promise<void>;
20
20
  export declare function runFastlane(fastlaneArgs: string[], { logger, env, cwd, }?: {
21
21
  logger?: bunyan;
22
- env?: Record<string, string>;
22
+ env?: Env;
23
23
  cwd?: string;
24
24
  }): Promise<SpawnResult>;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createSubmissionEntityFunction = createSubmissionEntityFunction;
4
4
  const results_1 = require("@expo/results");
5
5
  const steps_1 = require("@expo/steps");
6
+ const sentry_1 = require("../../sentry");
6
7
  const retryOnDNSFailure_1 = require("../../utils/retryOnDNSFailure");
7
8
  function createSubmissionEntityFunction() {
8
9
  return new steps_1.BuildFunction({
@@ -53,16 +54,39 @@ function createSubmissionEntityFunction() {
53
54
  const robotAccessToken = stepsCtx.global.staticContext.job.secrets?.robotAccessToken;
54
55
  if (!robotAccessToken) {
55
56
  stepsCtx.logger.error('Failed to create submission entity: no robot access token found');
57
+ sentry_1.Sentry.capture('Failed to create submission entity: missing robot access token');
56
58
  return;
57
59
  }
58
60
  const buildId = inputs.build_id.value;
59
61
  if (!buildId) {
60
62
  stepsCtx.logger.error('Failed to create submission entity: no build ID provided');
63
+ sentry_1.Sentry.capture('Failed to create submission entity: missing build ID', {
64
+ extras: {
65
+ buildId,
66
+ },
67
+ });
61
68
  return;
62
69
  }
63
70
  const workflowJobId = stepsCtx.global.env.__WORKFLOW_JOB_ID;
64
71
  if (!workflowJobId) {
65
72
  stepsCtx.logger.error('Failed to create submission entity: no workflow job ID found');
73
+ sentry_1.Sentry.capture('Failed to create submission entity: missing workflow job ID', {
74
+ extras: {
75
+ buildId,
76
+ workflowJobId,
77
+ },
78
+ });
79
+ return;
80
+ }
81
+ const expoApiServerURL = stepsCtx.global.staticContext.expoApiServerURL;
82
+ if (!expoApiServerURL) {
83
+ stepsCtx.logger.error('Failed to create submission entity: no Expo API server URL found');
84
+ sentry_1.Sentry.capture('Failed to create submission entity: missing Expo API server URL', {
85
+ extras: {
86
+ buildId,
87
+ workflowJobId,
88
+ },
89
+ });
66
90
  return;
67
91
  }
68
92
  // This is supposed to provide fallback for `''` -> `undefined`.
@@ -76,7 +100,7 @@ function createSubmissionEntityFunction() {
76
100
  const ascAppIdentifier = inputs.asc_app_identifier.value || undefined;
77
101
  /* eslint-enable @typescript-eslint/prefer-nullish-coalescing */
78
102
  try {
79
- const response = await (0, retryOnDNSFailure_1.retryOnDNSFailure)(fetch)(new URL('/v2/app-store-submissions/', stepsCtx.global.staticContext.expoApiServerURL), {
103
+ const response = await (0, retryOnDNSFailure_1.retryOnDNSFailure)(fetch)(new URL('/v2/app-store-submissions/', expoApiServerURL), {
80
104
  method: 'POST',
81
105
  headers: {
82
106
  Authorization: `Bearer ${robotAccessToken}`,
@@ -52,11 +52,21 @@ function createDownloadArtifactFunction() {
52
52
  });
53
53
  const interpolationContext = stepsCtx.global.getInterpolationContext();
54
54
  if (!('workflow' in interpolationContext)) {
55
- throw new eas_build_job_1.UserError('EAS_DOWNLOAD_ARTIFACT_NO_WORKFLOW', 'No workflow found in the interpolation context.');
55
+ throw new eas_build_job_1.SystemError('No workflow found in the interpolation context.', {
56
+ trackingCode: 'EAS_DOWNLOAD_ARTIFACT_NO_WORKFLOW',
57
+ });
56
58
  }
57
59
  const robotAccessToken = stepsCtx.global.staticContext.job.secrets?.robotAccessToken;
58
60
  if (!robotAccessToken) {
59
- throw new eas_build_job_1.UserError('EAS_DOWNLOAD_ARTIFACT_NO_ROBOT_ACCESS_TOKEN', 'No robot access token found in the job secrets.');
61
+ throw new eas_build_job_1.SystemError('No robot access token found in the job secrets.', {
62
+ trackingCode: 'EAS_DOWNLOAD_ARTIFACT_NO_ROBOT_ACCESS_TOKEN',
63
+ });
64
+ }
65
+ const expoApiServerURL = stepsCtx.global.staticContext.expoApiServerURL;
66
+ if (!expoApiServerURL) {
67
+ throw new eas_build_job_1.SystemError('Missing Expo API server URL.', {
68
+ trackingCode: 'EAS_DOWNLOAD_ARTIFACT_NO_EXPO_API_SERVER_URL',
69
+ });
60
70
  }
61
71
  const workflowRunId = interpolationContext.workflow.id;
62
72
  const { logger } = stepsCtx;
@@ -69,7 +79,7 @@ function createDownloadArtifactFunction() {
69
79
  const { artifactPath } = await downloadArtifactAsync({
70
80
  logger,
71
81
  workflowRunId,
72
- expoApiServerURL: stepsCtx.global.staticContext.expoApiServerURL,
82
+ expoApiServerURL,
73
83
  robotAccessToken,
74
84
  params,
75
85
  });
@@ -33,11 +33,6 @@ function createRepackBuildFunction() {
33
33
  required: false,
34
34
  allowedValueTypeName: steps_1.BuildStepInputValueTypeName.STRING,
35
35
  }),
36
- steps_1.BuildStepInput.createProvider({
37
- id: 'output_path',
38
- allowedValueTypeName: steps_1.BuildStepInputValueTypeName.STRING,
39
- required: false,
40
- }),
41
36
  steps_1.BuildStepInput.createProvider({
42
37
  id: 'embed_bundle_assets',
43
38
  allowedValueTypeName: steps_1.BuildStepInputValueTypeName.BOOLEAN,
@@ -93,8 +88,10 @@ function createRepackBuildFunction() {
93
88
  await node_fs_1.default.promises.mkdir(workingDirectory);
94
89
  stepsCtx.logger.info(`Created temporary working directory: ${workingDirectory}`);
95
90
  const sourceAppPath = inputs.source_app_path.value;
96
- const outputPath = inputs.output_path.value ??
97
- node_path_1.default.join(tmpDir, `repacked-${(0, node_crypto_1.randomUUID)()}${node_path_1.default.extname(sourceAppPath)}`);
91
+ const outputPath = createOutputPath({
92
+ sourceAppPath,
93
+ tmpDir,
94
+ });
98
95
  const exportEmbedOptions = inputs.embed_bundle_assets.value
99
96
  ? {
100
97
  sourcemapOutput: undefined,
@@ -174,6 +171,14 @@ function createRepackBuildFunction() {
174
171
  },
175
172
  });
176
173
  }
174
+ function createOutputPath({ sourceAppPath, tmpDir, }) {
175
+ const outputPath = node_path_1.default.join(tmpDir, `repacked-${(0, node_crypto_1.randomUUID)()}${node_path_1.default.extname(sourceAppPath)}`);
176
+ const extension = node_path_1.default.extname(outputPath);
177
+ if (extension.toLowerCase() !== '.aab') {
178
+ return outputPath;
179
+ }
180
+ return `${outputPath.slice(0, -extension.length)}.apk`;
181
+ }
177
182
  /**
178
183
  * Install `@expo/repack-app` in a sandbox directory and import it.
179
184
  */
@@ -99,11 +99,12 @@ function createRestoreCacheFunction() {
99
99
  .parse((inputs.restore_keys.value ?? '').split(/[\r\n]+/))
100
100
  .filter(key => key !== '');
101
101
  const jobId = (0, nullthrows_1.default)(env.EAS_BUILD_ID, 'EAS_BUILD_ID is not set');
102
+ const expoApiServerURL = (0, nullthrows_1.default)(stepsCtx.global.staticContext.expoApiServerURL, 'expoApiServerURL is not set');
102
103
  const robotAccessToken = (0, nullthrows_1.default)(stepsCtx.global.staticContext.job.secrets?.robotAccessToken, 'robotAccessToken is not set');
103
104
  const { archivePath, matchedKey } = await downloadCacheAsync({
104
105
  logger,
105
106
  jobId,
106
- expoApiServerURL: stepsCtx.global.staticContext.expoApiServerURL,
107
+ expoApiServerURL,
107
108
  robotAccessToken,
108
109
  paths,
109
110
  key,
@@ -80,6 +80,7 @@ function createSaveCacheFunction() {
80
80
  .filter(path => path.length > 0);
81
81
  const key = zod_1.default.string().parse(inputs.key.value);
82
82
  const jobId = (0, nullthrows_1.default)(env.EAS_BUILD_ID, 'EAS_BUILD_ID is not set');
83
+ const expoApiServerURL = (0, nullthrows_1.default)(stepsCtx.global.staticContext.expoApiServerURL, 'expoApiServerURL is not set');
83
84
  const robotAccessToken = (0, nullthrows_1.default)(stepsCtx.global.staticContext.job.secrets?.robotAccessToken, 'robotAccessToken is not set');
84
85
  const { archivePath } = await compressCacheAsync({
85
86
  paths,
@@ -92,7 +93,7 @@ function createSaveCacheFunction() {
92
93
  await uploadPublicCacheAsync({
93
94
  logger,
94
95
  jobId,
95
- expoApiServerURL: stepsCtx.global.staticContext.expoApiServerURL,
96
+ expoApiServerURL,
96
97
  robotAccessToken,
97
98
  archivePath,
98
99
  key,
@@ -105,7 +106,7 @@ function createSaveCacheFunction() {
105
106
  await uploadCacheAsync({
106
107
  logger,
107
108
  jobId,
108
- expoApiServerURL: stepsCtx.global.staticContext.expoApiServerURL,
109
+ expoApiServerURL,
109
110
  robotAccessToken,
110
111
  archivePath,
111
112
  key,
@@ -26,6 +26,12 @@ function createStartIosSimulatorBuildFunction() {
26
26
  defaultValue: 1,
27
27
  allowedValueTypeName: steps_1.BuildStepInputValueTypeName.NUMBER,
28
28
  }),
29
+ steps_1.BuildStepInput.createProvider({
30
+ id: 'enable_accessibility_settings',
31
+ required: false,
32
+ defaultValue: false,
33
+ allowedValueTypeName: steps_1.BuildStepInputValueTypeName.BOOLEAN,
34
+ }),
29
35
  ],
30
36
  fn: async ({ logger }, { inputs, env }) => {
31
37
  try {
@@ -45,9 +51,16 @@ function createStartIosSimulatorBuildFunction() {
45
51
  }
46
52
  const deviceIdentifierInput = inputs.device_identifier.value?.toString();
47
53
  const originalDeviceIdentifier = deviceIdentifierInput ?? (await findMostGenericIphoneUuidAsync({ env }));
54
+ const enableAccessibilitySettings = Boolean(inputs.enable_accessibility_settings.value);
48
55
  if (!originalDeviceIdentifier) {
49
56
  throw new Error('Could not find an iPhone among available simulator devices.');
50
57
  }
58
+ if (enableAccessibilitySettings) {
59
+ await IosSimulatorUtils_1.IosSimulatorUtils.enableAccessibilitySettingsAsync({
60
+ deviceIdentifier: originalDeviceIdentifier,
61
+ env,
62
+ });
63
+ }
51
64
  const { udid } = await IosSimulatorUtils_1.IosSimulatorUtils.startAsync({
52
65
  deviceIdentifier: originalDeviceIdentifier,
53
66
  env,
@@ -78,6 +91,12 @@ function createStartIosSimulatorBuildFunction() {
78
91
  destinationDeviceName: cloneDeviceName,
79
92
  env,
80
93
  });
94
+ if (enableAccessibilitySettings) {
95
+ await IosSimulatorUtils_1.IosSimulatorUtils.enableAccessibilitySettingsAsync({
96
+ deviceIdentifier: cloneDeviceName,
97
+ env,
98
+ });
99
+ }
81
100
  const { udid: cloneUdid } = await IosSimulatorUtils_1.IosSimulatorUtils.startAsync({
82
101
  deviceIdentifier: cloneDeviceName,
83
102
  env,
@@ -39,6 +39,10 @@ export declare namespace IosSimulatorUtils {
39
39
  destinationDeviceName: IosSimulatorName;
40
40
  env: NodeJS.ProcessEnv;
41
41
  }): Promise<void>;
42
+ export function enableAccessibilitySettingsAsync({ deviceIdentifier, env, }: {
43
+ deviceIdentifier: IosSimulatorUuid | IosSimulatorName;
44
+ env: NodeJS.ProcessEnv;
45
+ }): Promise<void>;
42
46
  export function startAsync({ deviceIdentifier, env, }: {
43
47
  deviceIdentifier: IosSimulatorUuid | IosSimulatorName;
44
48
  env: NodeJS.ProcessEnv;
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.IosSimulatorUtils = void 0;
7
+ const eas_build_job_1 = require("@expo/eas-build-job");
7
8
  const turtle_spawn_1 = __importDefault(require("@expo/turtle-spawn"));
8
9
  const node_fs_1 = __importDefault(require("node:fs"));
9
10
  const node_os_1 = __importDefault(require("node:os"));
@@ -37,6 +38,45 @@ var IosSimulatorUtils;
37
38
  });
38
39
  }
39
40
  IosSimulatorUtils.cloneAsync = cloneAsync;
41
+ async function enableAccessibilitySettingsAsync({ deviceIdentifier, env, }) {
42
+ try {
43
+ const devices = await getAvailableDevicesAsync({ env, filter: 'available' });
44
+ const device = devices.find(device => device.isAvailable &&
45
+ (device.udid === deviceIdentifier || device.name === deviceIdentifier));
46
+ if (!device) {
47
+ throw new eas_build_job_1.UserError('EAS_IOS_SIMULATOR_NOT_FOUND', `Failed to find available iOS Simulator "${deviceIdentifier}" to update accessibility settings.`);
48
+ }
49
+ if (device.state !== 'Shutdown') {
50
+ throw new eas_build_job_1.UserError('EAS_IOS_SIMULATOR_NOT_SHUTDOWN', `Expected iOS Simulator "${deviceIdentifier}" to be shutdown before updating accessibility settings, but it is ${device.state}.`);
51
+ }
52
+ const plistPath = node_path_1.default.join(device.dataPath, 'Library', 'Preferences', 'com.apple.Accessibility.plist');
53
+ await node_fs_1.default.promises.mkdir(node_path_1.default.dirname(plistPath), { recursive: true });
54
+ const plistExists = await node_fs_1.default.promises
55
+ .access(plistPath)
56
+ .then(() => true)
57
+ .catch(() => false);
58
+ if (!plistExists) {
59
+ await (0, turtle_spawn_1.default)('plutil', ['-create', 'binary1', plistPath], { env });
60
+ }
61
+ for (const key of [
62
+ 'AutomationEnabled',
63
+ 'IgnoreAXServerEntitlements',
64
+ 'AccessibilityEnabled',
65
+ 'ApplicationAccessibilityEnabled',
66
+ ]) {
67
+ await (0, turtle_spawn_1.default)('plutil', ['-replace', key, '-bool', 'true', plistPath], { env });
68
+ }
69
+ }
70
+ catch (err) {
71
+ if (err instanceof eas_build_job_1.ExpoError) {
72
+ throw err;
73
+ }
74
+ throw new eas_build_job_1.SystemError('Failed to update iOS Simulator accessibility settings.', {
75
+ cause: err,
76
+ });
77
+ }
78
+ }
79
+ IosSimulatorUtils.enableAccessibilitySettingsAsync = enableAccessibilitySettingsAsync;
40
80
  async function startAsync({ deviceIdentifier, env, }) {
41
81
  const bootstatusResult = await (0, turtle_spawn_1.default)('xcrun', ['simctl', 'bootstatus', deviceIdentifier, '-b'], {
42
82
  env,
@@ -173,6 +173,11 @@ async function isEASUpdateConfigured(ctx) {
173
173
  }
174
174
  async function logDiffFingerprints({ resolvedRuntime, ctx, }) {
175
175
  const { resolvedRuntimeVersion, resolvedFingerprintSources } = resolvedRuntime;
176
+ const buildId = ctx.env.EAS_BUILD_ID;
177
+ if (!buildId) {
178
+ ctx.logger.warn('Skipping fingerprint diff because EAS_BUILD_ID is not set');
179
+ return;
180
+ }
176
181
  const fingerprintInfo = await ctx.graphqlClient
177
182
  .query((0, gql_tada_1.graphql)(`
178
183
  query GetFingerprintUrl($id: ID!) {
@@ -184,7 +189,7 @@ async function logDiffFingerprints({ resolvedRuntime, ctx, }) {
184
189
  }
185
190
  }
186
191
  }
187
- `), { id: ctx.env.EAS_BUILD_ID })
192
+ `), { id: buildId })
188
193
  .toPromise();
189
194
  if (fingerprintInfo.error) {
190
195
  ctx.logger.warn('Failed to fetch current fingerprint info', fingerprintInfo.error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expo/build-tools",
3
- "version": "20.4.0",
3
+ "version": "20.5.1",
4
4
  "bugs": "https://github.com/expo/eas-cli/issues",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "Expo <support@expo.io>",
@@ -38,14 +38,14 @@
38
38
  "@expo/config": "55.0.10",
39
39
  "@expo/config-plugins": "55.0.7",
40
40
  "@expo/downloader": "20.0.0",
41
- "@expo/eas-build-job": "20.1.0",
41
+ "@expo/eas-build-job": "20.5.1",
42
42
  "@expo/env": "^0.4.0",
43
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": "20.1.0",
48
+ "@expo/steps": "20.5.1",
49
49
  "@expo/template-file": "20.0.0",
50
50
  "@expo/turtle-spawn": "20.0.0",
51
51
  "@expo/xcpretty": "^4.3.1",
@@ -100,5 +100,5 @@
100
100
  "typescript": "^5.5.4",
101
101
  "uuid": "^9.0.1"
102
102
  },
103
- "gitHead": "f867b7b9f2641fe1db6924711cb705e663d40397"
103
+ "gitHead": "cd47185f29446299b7682d52cd917eb9a01038e7"
104
104
  }