eas-cli 2.5.1 → 2.7.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.
Files changed (150) hide show
  1. package/README.md +8 -1095
  2. package/build/branch/queries.d.ts +8 -1
  3. package/build/branch/queries.js +53 -23
  4. package/build/build/android/build.js +1 -0
  5. package/build/build/ios/build.js +1 -0
  6. package/build/build/local.js +1 -1
  7. package/build/build/queries.d.ts +11 -1
  8. package/build/build/queries.js +39 -1
  9. package/build/build/validate.d.ts +1 -0
  10. package/build/build/validate.js +121 -1
  11. package/build/channel/queries.d.ts +11 -0
  12. package/build/channel/queries.js +51 -9
  13. package/build/channel/utils.js +22 -22
  14. package/build/commandUtils/context/LoggedInContextField.d.ts +3 -0
  15. package/build/commandUtils/context/LoggedInContextField.js +9 -1
  16. package/build/commandUtils/context/MaybeLoggedInContextField.d.ts +3 -0
  17. package/build/commandUtils/context/MaybeLoggedInContextField.js +9 -1
  18. package/build/commandUtils/context/contextUtils/createGraphqlClient.d.ts +2 -2
  19. package/build/commandUtils/context/contextUtils/getProjectIdAsync.js +1 -1
  20. package/build/commandUtils/gating/FeatureGateEnvOverrides.d.ts +7 -0
  21. package/build/commandUtils/gating/FeatureGateEnvOverrides.js +35 -0
  22. package/build/commandUtils/gating/FeatureGateKey.d.ts +4 -0
  23. package/build/commandUtils/gating/FeatureGateKey.js +11 -0
  24. package/build/commandUtils/gating/FeatureGateTestOverrides.d.ts +5 -0
  25. package/build/commandUtils/gating/FeatureGateTestOverrides.js +17 -0
  26. package/build/commandUtils/gating/FeatureGating.d.ts +16 -0
  27. package/build/commandUtils/gating/FeatureGating.js +55 -0
  28. package/build/commandUtils/pagination.d.ts +4 -3
  29. package/build/commands/branch/create.d.ts +0 -3
  30. package/build/commands/branch/create.js +2 -27
  31. package/build/commands/branch/list.d.ts +1 -1
  32. package/build/commands/branch/view.d.ts +1 -1
  33. package/build/commands/build/configure.d.ts +1 -1
  34. package/build/commands/build/index.d.ts +2 -2
  35. package/build/commands/build/list.d.ts +4 -4
  36. package/build/commands/build/list.js +2 -15
  37. package/build/commands/build/run.d.ts +21 -0
  38. package/build/commands/build/run.js +149 -0
  39. package/build/commands/build/version/set.d.ts +1 -1
  40. package/build/commands/build/version/sync.d.ts +1 -1
  41. package/build/commands/channel/create.d.ts +0 -7
  42. package/build/commands/channel/create.js +4 -31
  43. package/build/commands/channel/list.d.ts +1 -1
  44. package/build/commands/channel/view.d.ts +1 -1
  45. package/build/commands/config.d.ts +1 -1
  46. package/build/commands/credentials.d.ts +1 -1
  47. package/build/commands/device/list.d.ts +1 -1
  48. package/build/commands/metadata/lint.d.ts +12 -0
  49. package/build/commands/metadata/lint.js +72 -0
  50. package/build/commands/metadata/pull.js +20 -9
  51. package/build/commands/metadata/push.js +20 -9
  52. package/build/commands/secret/create.d.ts +1 -1
  53. package/build/commands/secret/list.js +12 -17
  54. package/build/commands/submit.d.ts +1 -1
  55. package/build/commands/update/configure.d.ts +1 -0
  56. package/build/commands/update/configure.js +10 -216
  57. package/build/commands/update/index.d.ts +3 -9
  58. package/build/commands/update/index.js +136 -143
  59. package/build/commands/update/list.d.ts +1 -1
  60. package/build/commands/webhook/create.d.ts +1 -1
  61. package/build/commands/webhook/list.d.ts +1 -1
  62. package/build/commands/webhook/update.d.ts +1 -1
  63. package/build/devices/actions/create/inputMethod.js +2 -15
  64. package/build/devices/utils/formatDevice.d.ts +2 -0
  65. package/build/devices/utils/formatDevice.js +32 -7
  66. package/build/env.d.ts +8 -0
  67. package/build/env.js +8 -0
  68. package/build/graphql/generated.d.ts +100 -23
  69. package/build/graphql/generated.js +10 -2
  70. package/build/graphql/mutations/KeystoreGenerationUrlMutation.js +1 -1
  71. package/build/graphql/queries/UserQuery.js +2 -2
  72. package/build/graphql/types/Build.js +2 -0
  73. package/build/log.d.ts +1 -0
  74. package/build/log.js +3 -0
  75. package/build/metadata/apple/rules/index.d.ts +1 -0
  76. package/build/metadata/apple/rules/index.js +6 -0
  77. package/build/metadata/apple/rules/infoKeywordLength.d.ts +6 -0
  78. package/build/metadata/apple/rules/infoKeywordLength.js +35 -0
  79. package/build/metadata/apple/rules/infoRestrictedWords.d.ts +6 -0
  80. package/build/metadata/apple/rules/infoRestrictedWords.js +57 -0
  81. package/build/metadata/apple/tasks/index.d.ts +1 -2
  82. package/build/metadata/apple/tasks/index.js +1 -1
  83. package/build/metadata/auth.d.ts +21 -0
  84. package/build/metadata/auth.js +33 -0
  85. package/build/metadata/config/issue.d.ts +21 -0
  86. package/build/metadata/config/issue.js +9 -0
  87. package/build/metadata/config/resolve.d.ts +27 -0
  88. package/build/metadata/{config.js → config/resolve.js} +24 -25
  89. package/build/metadata/config/schema.d.ts +7 -0
  90. package/build/metadata/config/schema.js +2 -0
  91. package/build/metadata/config/validate.d.ts +3 -0
  92. package/build/metadata/config/validate.js +47 -0
  93. package/build/metadata/download.d.ts +11 -2
  94. package/build/metadata/download.js +14 -9
  95. package/build/metadata/errors.d.ts +3 -3
  96. package/build/metadata/errors.js +3 -1
  97. package/build/metadata/upload.d.ts +11 -2
  98. package/build/metadata/upload.js +16 -11
  99. package/build/metadata/utils/ajv.d.ts +10 -0
  100. package/build/metadata/utils/ajv.js +30 -0
  101. package/build/metadata/utils/telemetry.js +6 -6
  102. package/build/project/projectUtils.d.ts +3 -1
  103. package/build/project/projectUtils.js +10 -3
  104. package/build/project/publish.d.ts +13 -10
  105. package/build/project/publish.js +68 -38
  106. package/build/project/workflow.d.ts +1 -0
  107. package/build/project/workflow.js +9 -1
  108. package/build/run/android/run.d.ts +1 -0
  109. package/build/run/android/run.js +9 -0
  110. package/build/run/ios/run.d.ts +1 -0
  111. package/build/run/ios/run.js +31 -0
  112. package/build/run/ios/simctl.d.ts +2 -0
  113. package/build/run/ios/simctl.js +8 -0
  114. package/build/run/ios/simulator.d.ts +21 -0
  115. package/build/run/ios/simulator.js +161 -0
  116. package/build/run/ios/systemRequirements.d.ts +1 -0
  117. package/build/run/ios/systemRequirements.js +82 -0
  118. package/build/run/ios/xcode.d.ts +4 -0
  119. package/build/run/ios/xcode.js +41 -0
  120. package/build/run/ios/xcrun.d.ts +4 -0
  121. package/build/run/ios/xcrun.js +68 -0
  122. package/build/run/run.d.ts +8 -0
  123. package/build/run/run.js +15 -0
  124. package/build/submit/ArchiveSource.js +12 -16
  125. package/build/submit/utils/summary.d.ts +1 -1
  126. package/build/update/configure.d.ts +22 -0
  127. package/build/update/configure.js +200 -0
  128. package/build/update/queries.js +30 -39
  129. package/build/update/utils.d.ts +8 -1
  130. package/build/update/utils.js +35 -1
  131. package/build/utils/buildDistribution.d.ts +3 -0
  132. package/build/utils/buildDistribution.js +20 -0
  133. package/build/utils/download.d.ts +2 -0
  134. package/build/utils/download.js +114 -0
  135. package/build/utils/expoCli.d.ts +6 -0
  136. package/build/utils/expoCli.js +46 -1
  137. package/build/utils/expodash/filter.d.ts +2 -0
  138. package/build/utils/expodash/filter.js +8 -0
  139. package/build/utils/expodash/memoize.d.ts +2 -0
  140. package/build/utils/expodash/memoize.js +17 -0
  141. package/build/utils/formatFields.d.ts +3 -2
  142. package/build/utils/image.d.ts +6 -0
  143. package/build/utils/image.js +107 -0
  144. package/build/utils/statuspageService.js +1 -0
  145. package/oclif.manifest.json +1 -1
  146. package/package.json +36 -30
  147. package/schema/metadata-0.json +1 -1
  148. package/build/metadata/config.d.ts +0 -41
  149. package/build/metadata/context.d.ts +0 -50
  150. package/build/metadata/context.js +0 -47
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isUploadedAssetCountAboveWarningThreshold = exports.uploadAssetsAsync = exports.filterOutAssetsThatAlreadyExistAsync = exports.collectAssetsAsync = exports.loadMetadata = exports.resolveInputDirectoryAsync = exports.buildBundlesAsync = exports.buildUnsortedUpdateInfoGroupAsync = exports.convertAssetToUpdateInfoGroupFormatAsync = exports.getStorageKeyForAssetAsync = exports.getStorageKey = exports.getBase64URLEncoding = exports.guessContentTypeFromExtension = exports.MetadataJoi = void 0;
3
+ exports.isUploadedAssetCountAboveWarningThreshold = exports.uploadAssetsAsync = exports.filterOutAssetsThatAlreadyExistAsync = exports.collectAssetsAsync = exports.filterExportedPlatformsByFlag = exports.loadMetadata = exports.resolveInputDirectoryAsync = exports.buildBundlesAsync = exports.buildUnsortedUpdateInfoGroupAsync = exports.convertAssetToUpdateInfoGroupFormatAsync = exports.getStorageKeyForAssetAsync = exports.getStorageKey = exports.getBase64URLEncoding = exports.guessContentTypeFromExtension = exports.MetadataJoi = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const json_file_1 = tslib_1.__importDefault(require("@expo/json-file"));
6
6
  const crypto_1 = tslib_1.__importDefault(require("crypto"));
@@ -12,6 +12,7 @@ const promise_limit_1 = tslib_1.__importDefault(require("promise-limit"));
12
12
  const generated_1 = require("../graphql/generated");
13
13
  const PublishMutation_1 = require("../graphql/mutations/PublishMutation");
14
14
  const PublishQuery_1 = require("../graphql/queries/PublishQuery");
15
+ const log_1 = tslib_1.__importDefault(require("../log"));
15
16
  const uploads_1 = require("../uploads");
16
17
  const expoCli_1 = require("../utils/expoCli");
17
18
  const chunk_1 = tslib_1.__importDefault(require("../utils/expodash/chunk"));
@@ -21,13 +22,14 @@ const fileMetadataJoi = joi_1.default.object({
21
22
  .required()
22
23
  .items(joi_1.default.object({ path: joi_1.default.string().required(), ext: joi_1.default.string().required() })),
23
24
  bundle: joi_1.default.string().required(),
24
- }).required();
25
+ }).optional();
25
26
  exports.MetadataJoi = joi_1.default.object({
26
27
  version: joi_1.default.number().required(),
27
28
  bundler: joi_1.default.string().required(),
28
29
  fileMetadata: joi_1.default.object({
29
30
  android: fileMetadataJoi,
30
31
  ios: fileMetadataJoi,
32
+ web: fileMetadataJoi,
31
33
  }).required(),
32
34
  }).required();
33
35
  function guessContentTypeFromExtension(ext) {
@@ -102,29 +104,44 @@ async function buildUnsortedUpdateInfoGroupAsync(assets, exp) {
102
104
  return updateInfoGroup;
103
105
  }
104
106
  exports.buildUnsortedUpdateInfoGroupAsync = buildUnsortedUpdateInfoGroupAsync;
105
- async function buildBundlesAsync({ projectDir, inputDir, }) {
107
+ async function buildBundlesAsync({ projectDir, inputDir, exp, platformFlag, }) {
106
108
  const packageJSON = json_file_1.default.read(path_1.default.resolve(projectDir, 'package.json'));
107
109
  if (!packageJSON) {
108
110
  throw new Error('Could not locate package.json');
109
111
  }
110
- await (0, expoCli_1.expoCommandAsync)(projectDir, [
111
- 'export',
112
- '--output-dir',
113
- inputDir,
114
- '--experimental-bundle',
115
- '--non-interactive',
116
- '--dump-sourcemap',
117
- ]);
112
+ if ((0, expoCli_1.shouldUseVersionedExpoCLI)(projectDir, exp)) {
113
+ await (0, expoCli_1.expoCommandAsync)(projectDir, [
114
+ 'export',
115
+ '--output-dir',
116
+ inputDir,
117
+ '--dump-sourcemap',
118
+ '--platform',
119
+ platformFlag,
120
+ ]);
121
+ }
122
+ else {
123
+ // Legacy global Expo CLI
124
+ await (0, expoCli_1.expoCommandAsync)(projectDir, [
125
+ 'export',
126
+ '--output-dir',
127
+ inputDir,
128
+ '--experimental-bundle',
129
+ '--non-interactive',
130
+ '--dump-sourcemap',
131
+ '--platform',
132
+ platformFlag,
133
+ ]);
134
+ }
118
135
  }
119
136
  exports.buildBundlesAsync = buildBundlesAsync;
120
- async function resolveInputDirectoryAsync(customInputDirectory) {
121
- const distRoot = path_1.default.resolve(customInputDirectory);
137
+ async function resolveInputDirectoryAsync(inputDir, { skipBundler }) {
138
+ const distRoot = path_1.default.resolve(inputDir);
122
139
  if (!(await fs_extra_1.default.pathExists(distRoot))) {
123
- throw new Error(`The input directory "${customInputDirectory}" does not exist.
124
- You can allow us to build it for you by not setting the --skip-bundler flag.
125
- If you chose to build it yourself you'll need to run a command to build the JS
126
- bundle first.
127
- You can use '--input-dir' to specify a different input directory.`);
140
+ let error = `--input-dir="${inputDir}" not found.`;
141
+ if (skipBundler) {
142
+ error += ` --skip-bundler requires the project to be exported manually before uploading. Ex: npx expo export && eas update --skip-bundler`;
143
+ }
144
+ throw new Error(error);
128
145
  }
129
146
  return distRoot;
130
147
  }
@@ -143,37 +160,50 @@ function loadMetadata(distRoot) {
143
160
  if (metadata.bundler !== 'metro') {
144
161
  throw new Error('Only bundles created with Metro are currently supported');
145
162
  }
163
+ const platforms = Object.keys(metadata.fileMetadata);
164
+ if (platforms.length === 0) {
165
+ log_1.default.warn('No updates were exported for any platform');
166
+ }
167
+ log_1.default.debug(`Loaded ${platforms.length} platform(s): ${platforms.join(', ')}`);
146
168
  return metadata;
147
169
  }
148
170
  exports.loadMetadata = loadMetadata;
149
- async function collectAssetsAsync({ inputDir, platforms, }) {
150
- const distRoot = await resolveInputDirectoryAsync(inputDir);
151
- const metadata = loadMetadata(distRoot);
152
- const assetsFinal = {};
153
- for (const platform of platforms) {
154
- assetsFinal[platform] = {
171
+ function filterExportedPlatformsByFlag(record, platformFlag) {
172
+ if (platformFlag === 'all') {
173
+ return record;
174
+ }
175
+ const platform = platformFlag;
176
+ if (!record[platform]) {
177
+ throw new Error(`--platform="${platform}" not found in metadata.json. Available platform(s): ${Object.keys(record).join(', ')}`);
178
+ }
179
+ return { [platform]: record[platform] };
180
+ }
181
+ exports.filterExportedPlatformsByFlag = filterExportedPlatformsByFlag;
182
+ /** Given a directory, load the metadata.json and collect the assets for each platform. */
183
+ async function collectAssetsAsync(dir) {
184
+ const metadata = loadMetadata(dir);
185
+ const collectedAssets = {};
186
+ for (const platform of Object.keys(metadata.fileMetadata)) {
187
+ collectedAssets[platform] = {
155
188
  launchAsset: {
156
189
  fileExtension: '.bundle',
157
190
  contentType: 'application/javascript',
158
- path: path_1.default.resolve(distRoot, metadata.fileMetadata[platform].bundle),
191
+ path: path_1.default.resolve(dir, metadata.fileMetadata[platform].bundle),
159
192
  },
160
- assets: metadata.fileMetadata[platform].assets.map(asset => {
161
- let fileExtension;
162
- if (asset.ext) {
163
- // ensure the file extension has a '.' prefix
164
- fileExtension = asset.ext.startsWith('.') ? asset.ext : `.${asset.ext}`;
165
- }
166
- return {
167
- fileExtension,
168
- contentType: guessContentTypeFromExtension(asset.ext),
169
- path: path_1.default.join(distRoot, asset.path),
170
- };
171
- }),
193
+ assets: metadata.fileMetadata[platform].assets.map(asset => ({
194
+ fileExtension: asset.ext ? ensureLeadingPeriod(asset.ext) : undefined,
195
+ contentType: guessContentTypeFromExtension(asset.ext),
196
+ path: path_1.default.join(dir, asset.path),
197
+ })),
172
198
  };
173
199
  }
174
- return assetsFinal;
200
+ return collectedAssets;
175
201
  }
176
202
  exports.collectAssetsAsync = collectAssetsAsync;
203
+ // ensure the file extension has a '.' prefix
204
+ function ensureLeadingPeriod(extension) {
205
+ return extension.startsWith('.') ? extension : `.${extension}`;
206
+ }
177
207
  async function filterOutAssetsThatAlreadyExistAsync(graphqlClient, uniqueAssetsWithStorageKey) {
178
208
  const assetMetadata = await PublishQuery_1.PublishQuery.getAssetMetadataAsync(graphqlClient, uniqueAssetsWithStorageKey.map(asset => asset.storageKey));
179
209
  const missingAssetKeys = assetMetadata
@@ -1,2 +1,3 @@
1
1
  import { Platform, Workflow } from '@expo/eas-build-job';
2
2
  export declare function resolveWorkflowAsync(projectDir: string, platform: Platform): Promise<Workflow>;
3
+ export declare function resolveWorkflowPerPlatformAsync(projectDir: string): Promise<Record<Platform, Workflow>>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.resolveWorkflowAsync = void 0;
3
+ exports.resolveWorkflowPerPlatformAsync = exports.resolveWorkflowAsync = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const config_plugins_1 = require("@expo/config-plugins");
6
6
  const eas_build_job_1 = require("@expo/eas-build-job");
@@ -32,3 +32,11 @@ async function resolveWorkflowAsync(projectDir, platform) {
32
32
  return eas_build_job_1.Workflow.MANAGED;
33
33
  }
34
34
  exports.resolveWorkflowAsync = resolveWorkflowAsync;
35
+ async function resolveWorkflowPerPlatformAsync(projectDir) {
36
+ const [android, ios] = await Promise.all([
37
+ resolveWorkflowAsync(projectDir, eas_build_job_1.Platform.ANDROID),
38
+ resolveWorkflowAsync(projectDir, eas_build_job_1.Platform.IOS),
39
+ ]);
40
+ return { android, ios };
41
+ }
42
+ exports.resolveWorkflowPerPlatformAsync = resolveWorkflowPerPlatformAsync;
@@ -0,0 +1 @@
1
+ export declare function runAppOnAndroidEmulatorAsync(_appPath: string): Promise<void>;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runAppOnAndroidEmulatorAsync = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const log_1 = tslib_1.__importDefault(require("../../log"));
6
+ async function runAppOnAndroidEmulatorAsync(_appPath) {
7
+ log_1.default.error('Not implemented!');
8
+ }
9
+ exports.runAppOnAndroidEmulatorAsync = runAppOnAndroidEmulatorAsync;
@@ -0,0 +1 @@
1
+ export declare function runAppOnIosSimulatorAsync(appPath: string): Promise<void>;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runAppOnIosSimulatorAsync = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const spawn_async_1 = tslib_1.__importDefault(require("@expo/spawn-async"));
6
+ const path_1 = tslib_1.__importDefault(require("path"));
7
+ const simulator = tslib_1.__importStar(require("./simulator"));
8
+ const systemRequirements_1 = require("./systemRequirements");
9
+ async function runAppOnIosSimulatorAsync(appPath) {
10
+ await (0, systemRequirements_1.validateSystemRequirementsAsync)();
11
+ const selectedSimulator = await simulator.selectSimulatorAsync();
12
+ await simulator.ensureSimulatorBootedAsync(selectedSimulator);
13
+ await simulator.ensureSimulatorAppOpenedAsync(selectedSimulator.udid);
14
+ const bundleIdentifier = await getAppBundleIdentifierAsync(appPath);
15
+ await simulator.installAppAsync(selectedSimulator.udid, appPath);
16
+ await simulator.launchAppAsync(selectedSimulator.udid, bundleIdentifier);
17
+ }
18
+ exports.runAppOnIosSimulatorAsync = runAppOnIosSimulatorAsync;
19
+ async function getAppBundleIdentifierAsync(appPath) {
20
+ const { stdout, stderr } = await (0, spawn_async_1.default)('xcrun', [
21
+ 'plutil',
22
+ '-extract',
23
+ 'CFBundleIdentifier',
24
+ 'raw',
25
+ path_1.default.join(appPath, 'Info.plist'),
26
+ ]);
27
+ if (!stdout) {
28
+ throw new Error(`Could not read app bundle identifier from ${path_1.default.join(appPath, 'Info.plist')}: ${stderr}`);
29
+ }
30
+ return stdout.trim();
31
+ }
@@ -0,0 +1,2 @@
1
+ import { SpawnOptions, SpawnResult } from '@expo/spawn-async';
2
+ export declare function simctlAsync(args: string[], options?: SpawnOptions): Promise<SpawnResult>;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.simctlAsync = void 0;
4
+ const xcrun_1 = require("./xcrun");
5
+ async function simctlAsync(args, options) {
6
+ return (0, xcrun_1.xcrunAsync)(['simctl', ...args], options);
7
+ }
8
+ exports.simctlAsync = simctlAsync;
@@ -0,0 +1,21 @@
1
+ interface IosSimulator {
2
+ runtime: string;
3
+ osVersion: string;
4
+ windowName: string;
5
+ osType: 'iOS';
6
+ state: 'Booted' | 'Shutdown';
7
+ isAvailable: boolean;
8
+ name: string;
9
+ udid: string;
10
+ lastBootedAt?: Date;
11
+ }
12
+ export declare function selectSimulatorAsync(): Promise<IosSimulator>;
13
+ export declare function getFirstBootedIosSimulatorAsync(): Promise<IosSimulator | undefined>;
14
+ export declare function getAvaliableIosSimulatorsListAsync(query?: string): Promise<IosSimulator[]>;
15
+ export declare function ensureSimulatorBootedAsync(simulator: IosSimulator): Promise<void>;
16
+ export declare function openSimulatorAppAsync(simulatorUdid: string): Promise<void>;
17
+ export declare function launchAppAsync(simulatorUdid: string, bundleIdentifier: string): Promise<void>;
18
+ export declare function ensureSimulatorAppOpenedAsync(simulatorUuid: string): Promise<void>;
19
+ export declare function installAppAsync(deviceId: string, filePath: string): Promise<void>;
20
+ export declare function getSimulatorAppIdAsync(): Promise<string | undefined>;
21
+ export {};
@@ -0,0 +1,161 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getSimulatorAppIdAsync = exports.installAppAsync = exports.ensureSimulatorAppOpenedAsync = exports.launchAppAsync = exports.openSimulatorAppAsync = exports.ensureSimulatorBootedAsync = exports.getAvaliableIosSimulatorsListAsync = exports.getFirstBootedIosSimulatorAsync = exports.selectSimulatorAsync = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const osascript = tslib_1.__importStar(require("@expo/osascript"));
6
+ const spawn_async_1 = tslib_1.__importDefault(require("@expo/spawn-async"));
7
+ const log_1 = tslib_1.__importDefault(require("../../log"));
8
+ const prompts_1 = require("../../prompts");
9
+ const promise_1 = require("../../utils/promise");
10
+ const simctl_1 = require("./simctl");
11
+ async function selectSimulatorAsync() {
12
+ const bootedSimulator = await getFirstBootedIosSimulatorAsync();
13
+ if (bootedSimulator) {
14
+ return bootedSimulator;
15
+ }
16
+ const simulators = await getAvaliableIosSimulatorsListAsync();
17
+ log_1.default.newLine();
18
+ const { selectedSimulator } = await (0, prompts_1.promptAsync)({
19
+ type: 'select',
20
+ message: `Select a simulator to run your app on`,
21
+ name: 'selectedSimulator',
22
+ choices: simulators.map(simulator => ({
23
+ title: `ios ${simulator.osVersion} ${simulator.name}`,
24
+ value: simulator,
25
+ })),
26
+ });
27
+ return selectedSimulator;
28
+ }
29
+ exports.selectSimulatorAsync = selectSimulatorAsync;
30
+ async function getFirstBootedIosSimulatorAsync() {
31
+ const bootedSimulators = await getAvaliableIosSimulatorsListAsync('booted');
32
+ if (bootedSimulators.length > 0) {
33
+ return bootedSimulators[0];
34
+ }
35
+ return undefined;
36
+ }
37
+ exports.getFirstBootedIosSimulatorAsync = getFirstBootedIosSimulatorAsync;
38
+ async function getAvaliableIosSimulatorsListAsync(query) {
39
+ const { stdout } = query
40
+ ? await (0, simctl_1.simctlAsync)(['list', 'devices', '--json', query])
41
+ : await (0, simctl_1.simctlAsync)(['list', 'devices', '--json']);
42
+ const info = parseSimControlJsonResults(stdout);
43
+ const iosSimulators = [];
44
+ for (const runtime of Object.keys(info.devices)) {
45
+ // Given a string like 'com.apple.CoreSimulator.SimRuntime.tvOS-13-4'
46
+ const runtimeSuffix = runtime.split('com.apple.CoreSimulator.SimRuntime.').pop();
47
+ if (!runtimeSuffix) {
48
+ continue;
49
+ }
50
+ // Create an array [tvOS, 13, 4]
51
+ const [osType, ...osVersionComponents] = runtimeSuffix.split('-');
52
+ if (osType === 'iOS') {
53
+ // Join the end components [13, 4] -> '13.4'
54
+ const osVersion = osVersionComponents.join('.');
55
+ const sims = info.devices[runtime];
56
+ for (const device of sims) {
57
+ if (device.isAvailable) {
58
+ iosSimulators.push({
59
+ ...device,
60
+ runtime,
61
+ osVersion,
62
+ windowName: `${device.name} (${osVersion})`,
63
+ osType: 'iOS',
64
+ state: device.state,
65
+ lastBootedAt: device.lastBootedAt ? new Date(device.lastBootedAt) : undefined,
66
+ });
67
+ }
68
+ }
69
+ }
70
+ }
71
+ return iosSimulators;
72
+ }
73
+ exports.getAvaliableIosSimulatorsListAsync = getAvaliableIosSimulatorsListAsync;
74
+ function parseSimControlJsonResults(input) {
75
+ try {
76
+ return JSON.parse(input);
77
+ }
78
+ catch (error) {
79
+ // Nov 15, 2020: Observed this can happen when opening the simulator and the simulator prompts the user to update the xcode command line tools.
80
+ // Unexpected token I in JSON at position 0
81
+ if (error.message.includes('Unexpected token')) {
82
+ log_1.default.error(`Apple's simctl returned malformed JSON:\n${input}`);
83
+ }
84
+ throw error;
85
+ }
86
+ }
87
+ async function ensureSimulatorBootedAsync(simulator) {
88
+ if (simulator.state === 'Booted') {
89
+ return;
90
+ }
91
+ await (0, simctl_1.simctlAsync)(['boot', simulator.udid]);
92
+ }
93
+ exports.ensureSimulatorBootedAsync = ensureSimulatorBootedAsync;
94
+ async function openSimulatorAppAsync(simulatorUdid) {
95
+ const args = ['-a', 'Simulator'];
96
+ if (simulatorUdid) {
97
+ // This has no effect if the app is already running.
98
+ args.push('--args', '-CurrentDeviceUDID', simulatorUdid);
99
+ }
100
+ await (0, spawn_async_1.default)('open', args);
101
+ }
102
+ exports.openSimulatorAppAsync = openSimulatorAppAsync;
103
+ async function launchAppAsync(simulatorUdid, bundleIdentifier) {
104
+ log_1.default.newLine();
105
+ log_1.default.log('Launching your app...');
106
+ await (0, simctl_1.simctlAsync)(['launch', simulatorUdid, bundleIdentifier]);
107
+ log_1.default.succeed('Successfully launched your app!');
108
+ }
109
+ exports.launchAppAsync = launchAppAsync;
110
+ // I think the app can be open while no simulators are booted.
111
+ async function waitForSimulatorAppToStartAsync(maxWaitTimeMs, intervalMs) {
112
+ log_1.default.newLine();
113
+ log_1.default.log('Waiting for Simulator app to start...');
114
+ const startTime = Date.now();
115
+ while (Date.now() - startTime < maxWaitTimeMs) {
116
+ if (await isSimulatorAppRunningAsync()) {
117
+ return;
118
+ }
119
+ await (0, promise_1.sleepAsync)(Math.min(intervalMs, Math.max(maxWaitTimeMs - (Date.now() - startTime), 0)));
120
+ }
121
+ throw new Error('Timed out waiting for the iOS simulator to start.');
122
+ }
123
+ async function isSimulatorAppRunningAsync() {
124
+ try {
125
+ const result = await osascript.execAsync('tell app "System Events" to count processes whose name is "Simulator"');
126
+ if (result.trim() === '0') {
127
+ return false;
128
+ }
129
+ }
130
+ catch (error) {
131
+ if (error.message.includes('Application isn’t running')) {
132
+ return false;
133
+ }
134
+ throw error;
135
+ }
136
+ return true;
137
+ }
138
+ async function ensureSimulatorAppOpenedAsync(simulatorUuid) {
139
+ if (await isSimulatorAppRunningAsync()) {
140
+ return;
141
+ }
142
+ await openSimulatorAppAsync(simulatorUuid);
143
+ await waitForSimulatorAppToStartAsync(60 * 1000, 1000);
144
+ }
145
+ exports.ensureSimulatorAppOpenedAsync = ensureSimulatorAppOpenedAsync;
146
+ async function installAppAsync(deviceId, filePath) {
147
+ log_1.default.newLine();
148
+ log_1.default.log('Installing your app on the simulator...');
149
+ await (0, simctl_1.simctlAsync)(['install', deviceId, filePath]);
150
+ log_1.default.succeed('Successfully installed your app on the simulator!');
151
+ }
152
+ exports.installAppAsync = installAppAsync;
153
+ async function getSimulatorAppIdAsync() {
154
+ try {
155
+ return (await osascript.execAsync('id of app "Simulator"')).trim();
156
+ }
157
+ catch {
158
+ return undefined;
159
+ }
160
+ }
161
+ exports.getSimulatorAppIdAsync = getSimulatorAppIdAsync;
@@ -0,0 +1 @@
1
+ export declare function validateSystemRequirementsAsync(): Promise<void>;
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateSystemRequirementsAsync = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const spawn_async_1 = tslib_1.__importDefault(require("@expo/spawn-async"));
6
+ const chalk_1 = tslib_1.__importDefault(require("chalk"));
7
+ const semver_1 = tslib_1.__importDefault(require("semver"));
8
+ const log_1 = tslib_1.__importDefault(require("../../log"));
9
+ const prompts_1 = require("../../prompts");
10
+ const simulator_1 = require("./simulator");
11
+ const xcode = tslib_1.__importStar(require("./xcode"));
12
+ const xcrun_1 = require("./xcrun");
13
+ function assertPlatform() {
14
+ if (process.platform !== 'darwin') {
15
+ log_1.default.error('iOS simulator apps can only be run on macOS devices.');
16
+ throw Error('iOS simulator apps can only be run on macOS devices.');
17
+ }
18
+ }
19
+ async function assertCorrectXcodeVersionInstalledAsync() {
20
+ const xcodeVersion = await xcode.getXcodeVersionAsync();
21
+ if (!xcodeVersion) {
22
+ const { goToAppStore } = await (0, prompts_1.promptAsync)({
23
+ type: 'select',
24
+ message: 'Xcode needs to be installed, would you like to continue to the App Store?',
25
+ name: 'goToAppStore',
26
+ choices: [
27
+ { title: 'Yes', value: true },
28
+ { title: 'No', value: false },
29
+ ],
30
+ });
31
+ if (goToAppStore) {
32
+ await xcode.openAppStoreAsync(xcode.APP_STORE_ID);
33
+ }
34
+ throw Error('Please try again once Xcode is installed');
35
+ }
36
+ if (semver_1.default.lt(xcodeVersion, xcode.MIN_XCODE_VERSION)) {
37
+ throw Error(`Xcode version ${chalk_1.default.bold(xcodeVersion)} is too old. Please upgrade to version ${chalk_1.default.bold(xcode.MIN_XCODE_VERSION)} or higher.`);
38
+ }
39
+ }
40
+ async function ensureXcrunInstalledAsync() {
41
+ if (!(0, xcrun_1.isXcrunInstalledAsync)()) {
42
+ const { installXcrun } = await (0, prompts_1.promptAsync)({
43
+ type: 'select',
44
+ message: 'Xcode Command Line Tools need to be installed, continue?',
45
+ name: 'installXcrun',
46
+ choices: [
47
+ { title: 'Yes', value: true },
48
+ { title: 'No', value: false },
49
+ ],
50
+ });
51
+ if (installXcrun) {
52
+ await (0, xcrun_1.installXcrunAsync)();
53
+ return;
54
+ }
55
+ throw Error('Please try again once Xcode Command Line Tools are installed');
56
+ }
57
+ }
58
+ async function assertSimulatorAppInstalledAsync() {
59
+ const simulatorAppId = await (0, simulator_1.getSimulatorAppIdAsync)();
60
+ if (!simulatorAppId) {
61
+ throw new Error(`Can't determine id of Simulator app; the Simulator is most likely not installed on this machine. Run 'sudo xcode-select -s /Applications/Xcode.app'`);
62
+ }
63
+ if (simulatorAppId !== 'com.apple.iphonesimulator' &&
64
+ simulatorAppId !== 'com.apple.CoreSimulator.SimulatorTrampoline') {
65
+ throw new Error(`Simulator is installed but is identified as '${simulatorAppId}', can't recognize what that is`);
66
+ }
67
+ try {
68
+ // make sure we can run simctl
69
+ await (0, spawn_async_1.default)('xcrun', ['simctl', 'help']);
70
+ }
71
+ catch (error) {
72
+ log_1.default.warn(`Unable to run simctl:\n${error.toString()}`);
73
+ throw new Error('xcrun is not configured correctly. Ensure `sudo xcode-select --reset` works before running this command again.');
74
+ }
75
+ }
76
+ async function validateSystemRequirementsAsync() {
77
+ assertPlatform();
78
+ await assertCorrectXcodeVersionInstalledAsync();
79
+ await ensureXcrunInstalledAsync();
80
+ await assertSimulatorAppInstalledAsync();
81
+ }
82
+ exports.validateSystemRequirementsAsync = validateSystemRequirementsAsync;
@@ -0,0 +1,4 @@
1
+ export declare const MIN_XCODE_VERSION = "9.4.0";
2
+ export declare const APP_STORE_ID = "497799835";
3
+ export declare function getXcodeVersionAsync(): Promise<string | undefined>;
4
+ export declare function openAppStoreAsync(appId: string): Promise<void>;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.openAppStoreAsync = exports.getXcodeVersionAsync = exports.APP_STORE_ID = exports.MIN_XCODE_VERSION = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const spawn_async_1 = tslib_1.__importDefault(require("@expo/spawn-async"));
6
+ const chalk_1 = tslib_1.__importDefault(require("chalk"));
7
+ const semver_1 = tslib_1.__importDefault(require("semver"));
8
+ const log_1 = tslib_1.__importDefault(require("../../log"));
9
+ // Based on the RN docs (Aug 2020).
10
+ exports.MIN_XCODE_VERSION = '9.4.0';
11
+ exports.APP_STORE_ID = '497799835';
12
+ async function getXcodeVersionAsync() {
13
+ var _a;
14
+ try {
15
+ const { stdout } = await (0, spawn_async_1.default)('xcodebuild', ['-version']);
16
+ const version = (_a = stdout.match(/Xcode (\d+\.\d+)/)) === null || _a === void 0 ? void 0 : _a[1];
17
+ const semverFormattedVersion = `${version}.0`;
18
+ if (!semver_1.default.valid(semverFormattedVersion)) {
19
+ log_1.default.warn(`Xcode version ${chalk_1.default.bold(version)} is in unknown format. Expected format is ${chalk_1.default.bold('12.0')}.`);
20
+ return undefined;
21
+ }
22
+ return semverFormattedVersion;
23
+ }
24
+ catch {
25
+ // not installed
26
+ return undefined;
27
+ }
28
+ }
29
+ exports.getXcodeVersionAsync = getXcodeVersionAsync;
30
+ async function openAppStoreAsync(appId) {
31
+ const link = getAppStoreLink(appId);
32
+ await (0, spawn_async_1.default)(`open`, [link]);
33
+ }
34
+ exports.openAppStoreAsync = openAppStoreAsync;
35
+ function getAppStoreLink(appId) {
36
+ if (process.platform === 'darwin') {
37
+ // TODO: Is there ever a case where the macappstore isn't available on mac?
38
+ return `macappstore://itunes.apple.com/app/id${appId}`;
39
+ }
40
+ return `https://apps.apple.com/us/app/id${appId}`;
41
+ }
@@ -0,0 +1,4 @@
1
+ import { SpawnOptions, SpawnResult } from '@expo/spawn-async';
2
+ export declare function xcrunAsync(args: string[], options?: SpawnOptions): Promise<SpawnResult>;
3
+ export declare function isXcrunInstalledAsync(): Promise<boolean>;
4
+ export declare function installXcrunAsync(): Promise<void>;
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.installXcrunAsync = exports.isXcrunInstalledAsync = exports.xcrunAsync = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const spawn_async_1 = tslib_1.__importDefault(require("@expo/spawn-async"));
6
+ const chalk_1 = tslib_1.__importDefault(require("chalk"));
7
+ const log_1 = tslib_1.__importDefault(require("../../log"));
8
+ const promise_1 = require("../../utils/promise");
9
+ async function xcrunAsync(args, options) {
10
+ try {
11
+ return await (0, spawn_async_1.default)('xcrun', args, options);
12
+ }
13
+ catch (e) {
14
+ throwXcrunError(e);
15
+ }
16
+ }
17
+ exports.xcrunAsync = xcrunAsync;
18
+ function throwXcrunError(e) {
19
+ var _a;
20
+ if (isLicenseOutOfDate(e.stdout) || isLicenseOutOfDate(e.stderr)) {
21
+ throw new Error('Xcode license is not accepted. Please run `sudo xcodebuild -license`.');
22
+ }
23
+ else if ((_a = e.stderr) === null || _a === void 0 ? void 0 : _a.includes('not a developer tool or in PATH')) {
24
+ throw new Error(`You may need to run ${chalk_1.default.bold('sudo xcode-select -s /Applications/Xcode.app')} and try again.`);
25
+ }
26
+ if (Array.isArray(e.output)) {
27
+ e.message += '\n' + e.output.join('\n').trim();
28
+ }
29
+ else if (e.stderr) {
30
+ e.message += '\n' + e.stderr;
31
+ }
32
+ throw new Error(`Some other error occurred while running xcrun command.
33
+ ${e.message}`);
34
+ }
35
+ function isLicenseOutOfDate(text) {
36
+ if (!text) {
37
+ return false;
38
+ }
39
+ const lower = text.toLowerCase();
40
+ return lower.includes('xcode') && lower.includes('license');
41
+ }
42
+ async function isXcrunInstalledAsync() {
43
+ try {
44
+ await (0, spawn_async_1.default)('xcrun', ['--version']);
45
+ return true;
46
+ }
47
+ catch {
48
+ return false;
49
+ }
50
+ }
51
+ exports.isXcrunInstalledAsync = isXcrunInstalledAsync;
52
+ async function installXcrunAsync() {
53
+ await (0, spawn_async_1.default)('xcode-select', ['--install']);
54
+ await waitForXcrunInstallToFinishAsync(60 * 1000, 1000);
55
+ }
56
+ exports.installXcrunAsync = installXcrunAsync;
57
+ async function waitForXcrunInstallToFinishAsync(maxWaitTimeMs, intervalMs) {
58
+ log_1.default.newLine();
59
+ log_1.default.log('Waiting for Xcode Command Line Tools install to finish...');
60
+ const startTime = Date.now();
61
+ while (Date.now() - startTime < maxWaitTimeMs) {
62
+ if (await isXcrunInstalledAsync()) {
63
+ return;
64
+ }
65
+ await (0, promise_1.sleepAsync)(Math.min(intervalMs, Math.max(maxWaitTimeMs - (Date.now() - startTime), 0)));
66
+ }
67
+ throw new Error('Timed out waiting for Xcode Command Line Tools install to finish');
68
+ }
@@ -0,0 +1,8 @@
1
+ import { AppPlatform } from '../graphql/generated';
2
+ export interface RunArchiveFlags {
3
+ latest?: boolean;
4
+ id?: string;
5
+ path?: string;
6
+ url?: string;
7
+ }
8
+ export declare function runAsync(simulatorBuildPath: string, selectedPlatform: AppPlatform): Promise<void>;