eas-cli 0.49.0 → 0.52.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 (60) hide show
  1. package/README.md +44 -43
  2. package/build/build/build.d.ts +6 -2
  3. package/build/build/build.js +191 -104
  4. package/build/build/ios/build.js +3 -1
  5. package/build/build/ios/credentials.js +2 -6
  6. package/build/build/local.js +1 -1
  7. package/build/build/runBuildAndSubmit.js +5 -1
  8. package/build/commands/update/index.d.ts +1 -0
  9. package/build/commands/update/index.js +27 -3
  10. package/build/credentials/android/actions/CreateGoogleServiceAccountKey.js +24 -9
  11. package/build/credentials/context.js +5 -0
  12. package/build/credentials/ios/IosCredentialsProvider.d.ts +0 -2
  13. package/build/credentials/ios/IosCredentialsProvider.js +0 -1
  14. package/build/credentials/ios/actions/AscApiKeyUtils.js +0 -1
  15. package/build/credentials/ios/actions/ConfigureProvisioningProfile.js +1 -1
  16. package/build/credentials/ios/actions/CreateProvisioningProfile.js +1 -1
  17. package/build/credentials/ios/actions/SetUpBuildCredentials.d.ts +0 -2
  18. package/build/credentials/ios/actions/SetUpBuildCredentials.js +3 -1
  19. package/build/credentials/ios/actions/SetUpTargetBuildCredentials.d.ts +2 -2
  20. package/build/credentials/ios/actions/SetUpTargetBuildCredentials.js +2 -2
  21. package/build/credentials/ios/appstore/AppStoreApi.d.ts +5 -1
  22. package/build/credentials/ios/appstore/AppStoreApi.js +38 -15
  23. package/build/credentials/ios/appstore/ascApiKey.d.ts +21 -5
  24. package/build/credentials/ios/appstore/ascApiKey.js +28 -12
  25. package/build/credentials/ios/appstore/authenticate.d.ts +9 -18
  26. package/build/credentials/ios/appstore/authenticate.js +43 -3
  27. package/build/credentials/ios/appstore/authenticateTypes.d.ts +42 -0
  28. package/build/credentials/ios/appstore/authenticateTypes.js +16 -0
  29. package/build/credentials/ios/appstore/contractMessages.d.ts +3 -0
  30. package/build/credentials/ios/appstore/contractMessages.js +12 -0
  31. package/build/credentials/ios/appstore/distributionCertificate.d.ts +1 -1
  32. package/build/credentials/ios/appstore/ensureAppExists.d.ts +2 -2
  33. package/build/credentials/ios/appstore/ensureAppExists.js +12 -5
  34. package/build/credentials/ios/appstore/provisioningProfile.d.ts +1 -1
  35. package/build/credentials/ios/appstore/provisioningProfileAdhoc.d.ts +1 -1
  36. package/build/credentials/ios/appstore/pushKey.d.ts +4 -4
  37. package/build/credentials/ios/appstore/pushKey.js +8 -8
  38. package/build/credentials/ios/appstore/resolveCredentials.d.ts +10 -1
  39. package/build/credentials/ios/appstore/resolveCredentials.js +125 -3
  40. package/build/credentials/ios/types.d.ts +2 -0
  41. package/build/credentials/ios/utils/printCredentials.d.ts +1 -1
  42. package/build/credentials/manager/ManageIos.js +8 -7
  43. package/build/graphql/generated.d.ts +73 -0
  44. package/build/graphql/generated.js +16 -1
  45. package/build/graphql/types/Build.js +4 -0
  46. package/build/project/ios/entitlements.d.ts +8 -0
  47. package/build/{credentials/ios/appstore → project/ios}/entitlements.js +7 -19
  48. package/build/project/ios/target.d.ts +9 -3
  49. package/build/project/ios/target.js +68 -47
  50. package/build/project/publish.js +2 -1
  51. package/build/submit/android/ServiceAccountSource.js +1 -1
  52. package/build/submit/ios/AppProduce.d.ts +0 -1
  53. package/build/submit/ios/AppProduce.js +5 -6
  54. package/build/submit/ios/AppSpecificPasswordSource.js +2 -2
  55. package/build/submit/utils/errors.js +6 -2
  56. package/build/utils/code-signing.d.ts +0 -5
  57. package/build/utils/code-signing.js +16 -65
  58. package/oclif.manifest.json +1 -1
  59. package/package.json +11 -11
  60. package/build/credentials/ios/appstore/entitlements.d.ts +0 -4
@@ -4,9 +4,12 @@ exports.waitForBuildEndAsync = exports.prepareBuildRequestForPlatformAsync = voi
4
4
  const tslib_1 = require("tslib");
5
5
  const eas_build_job_1 = require("@expo/eas-build-job");
6
6
  const chalk_1 = tslib_1.__importDefault(require("chalk"));
7
+ const cli_progress_1 = tslib_1.__importDefault(require("cli-progress"));
7
8
  const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
9
+ const nullthrows_1 = tslib_1.__importDefault(require("nullthrows"));
8
10
  const common_1 = require("../analytics/common");
9
11
  const events_1 = require("../analytics/events");
12
+ const api_1 = require("../api");
10
13
  const generated_1 = require("../graphql/generated");
11
14
  const BuildQuery_1 = require("../graphql/queries/BuildQuery");
12
15
  const log_1 = tslib_1.__importStar(require("../log"));
@@ -54,7 +57,6 @@ async function prepareBuildRequestForPlatformAsync(builder) {
54
57
  credentials: credentialsResult === null || credentialsResult === void 0 ? void 0 : credentialsResult.credentials,
55
58
  });
56
59
  return async () => {
57
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
58
60
  if (ctx.localBuildOptions.enable) {
59
61
  await (0, local_1.runLocalBuildAsync)(job, ctx.localBuildOptions);
60
62
  return undefined;
@@ -64,31 +66,35 @@ async function prepareBuildRequestForPlatformAsync(builder) {
64
66
  return await sendBuildRequestAsync(builder, job, metadata);
65
67
  }
66
68
  catch (error) {
67
- if (((_c = (_b = (_a = error === null || error === void 0 ? void 0 : error.graphQLErrors) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.extensions) === null || _c === void 0 ? void 0 : _c.errorCode) === 'TURTLE_DEPRECATED_JOB_FORMAT') {
68
- log_1.default.error('EAS Build API has changed, please upgrade to the latest eas-cli version.');
69
- throw new Error('Build request failed.');
70
- }
71
- else if (((_f = (_e = (_d = error === null || error === void 0 ? void 0 : error.graphQLErrors) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.extensions) === null || _f === void 0 ? void 0 : _f.errorCode) === 'EAS_BUILD_DOWN_FOR_MAINTENANCE') {
72
- log_1.default.error('EAS Build is down for maintenance, please try again later. Check https://status.expo.dev/ for updates.');
73
- throw new Error('Build request failed.');
74
- }
75
- else if (((_j = (_h = (_g = error === null || error === void 0 ? void 0 : error.graphQLErrors) === null || _g === void 0 ? void 0 : _g[0]) === null || _h === void 0 ? void 0 : _h.extensions) === null || _j === void 0 ? void 0 : _j.errorCode) === 'EAS_BUILD_FREE_TIER_DISABLED') {
76
- log_1.default.error('EAS Build free tier is temporarily disabled, please try again later. Check https://status.expo.dev/ for updates.');
77
- throw new Error('Build request failed.');
78
- }
79
- else if (((_m = (_l = (_k = error === null || error === void 0 ? void 0 : error.graphQLErrors) === null || _k === void 0 ? void 0 : _k[0]) === null || _l === void 0 ? void 0 : _l.extensions) === null || _m === void 0 ? void 0 : _m.errorCode) === 'EAS_BUILD_TOO_MANY_PENDING_BUILDS') {
80
- log_1.default.error(`You have already reached the maximum number of pending ${platform_1.requestedPlatformDisplayNames[job.platform]} builds for your account. Try again later.`);
81
- throw new Error('Build request failed.');
82
- }
83
- else if (error === null || error === void 0 ? void 0 : error.graphQLErrors) {
84
- log_1.default.error('Build request failed. Make sure you are using the latest eas-cli version. If the problem persists, please report the issue.');
85
- }
86
- throw error;
69
+ handleBuildRequestError(error, job.platform);
87
70
  }
88
71
  }
89
72
  };
90
73
  }
91
74
  exports.prepareBuildRequestForPlatformAsync = prepareBuildRequestForPlatformAsync;
75
+ function handleBuildRequestError(error, platform) {
76
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
77
+ if (((_c = (_b = (_a = error === null || error === void 0 ? void 0 : error.graphQLErrors) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.extensions) === null || _c === void 0 ? void 0 : _c.errorCode) === 'TURTLE_DEPRECATED_JOB_FORMAT') {
78
+ log_1.default.error('EAS Build API has changed, please upgrade to the latest eas-cli version.');
79
+ throw new Error('Build request failed.');
80
+ }
81
+ else if (((_f = (_e = (_d = error === null || error === void 0 ? void 0 : error.graphQLErrors) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.extensions) === null || _f === void 0 ? void 0 : _f.errorCode) === 'EAS_BUILD_DOWN_FOR_MAINTENANCE') {
82
+ log_1.default.error('EAS Build is down for maintenance, please try again later. Check https://status.expo.dev/ for updates.');
83
+ throw new Error('Build request failed.');
84
+ }
85
+ else if (((_j = (_h = (_g = error === null || error === void 0 ? void 0 : error.graphQLErrors) === null || _g === void 0 ? void 0 : _g[0]) === null || _h === void 0 ? void 0 : _h.extensions) === null || _j === void 0 ? void 0 : _j.errorCode) === 'EAS_BUILD_FREE_TIER_DISABLED') {
86
+ log_1.default.error('EAS Build free tier is temporarily disabled, please try again later. Check https://status.expo.dev/ for updates.');
87
+ throw new Error('Build request failed.');
88
+ }
89
+ else if (((_m = (_l = (_k = error === null || error === void 0 ? void 0 : error.graphQLErrors) === null || _k === void 0 ? void 0 : _k[0]) === null || _l === void 0 ? void 0 : _l.extensions) === null || _m === void 0 ? void 0 : _m.errorCode) === 'EAS_BUILD_TOO_MANY_PENDING_BUILDS') {
90
+ log_1.default.error(`You have already reached the maximum number of pending ${platform_1.requestedPlatformDisplayNames[platform]} builds for your account. Try again later.`);
91
+ throw new Error('Build request failed.');
92
+ }
93
+ else if (error === null || error === void 0 ? void 0 : error.graphQLErrors) {
94
+ log_1.default.error('Build request failed. Make sure you are using the latest eas-cli version. If the problem persists, please report the issue.');
95
+ }
96
+ throw error;
97
+ }
92
98
  async function uploadProjectAsync(ctx) {
93
99
  let projectTarballPath;
94
100
  try {
@@ -130,96 +136,177 @@ async function sendBuildRequestAsync(builder, job, metadata) {
130
136
  trackingCtx: ctx.trackingCtx,
131
137
  });
132
138
  }
133
- async function waitForBuildEndAsync(buildIds, { timeoutSec = 3600, intervalSec = 30 } = {}) {
134
- log_1.default.log(`Waiting for build${buildIds.length > 1 ? 's' : ''} to complete. You can press Ctrl+C to exit.`);
135
- const spinner = (0, ora_1.ora)().start();
136
- let time = new Date().getTime();
137
- const endTime = time + timeoutSec * 1000;
138
- while (time <= endTime) {
139
- const builds = await Promise.all(buildIds.map(async (buildId) => {
140
- try {
141
- return await BuildQuery_1.BuildQuery.byIdAsync(buildId, { useCache: false });
142
- }
143
- catch (err) {
144
- log_1.default.debug('Failed to fetch the build status', err);
145
- return null;
146
- }
147
- }));
148
- if (builds.length === 1) {
149
- const [build] = builds;
150
- if (build !== null) {
151
- switch (build.status) {
152
- case generated_1.BuildStatus.Finished:
153
- spinner.succeed('Build finished');
154
- return builds;
155
- case generated_1.BuildStatus.New:
156
- spinner.text = 'Build created';
157
- break;
158
- case generated_1.BuildStatus.InQueue:
159
- spinner.text = 'Build queued...';
160
- break;
161
- case generated_1.BuildStatus.Canceled:
162
- spinner.text = 'Build canceled';
163
- spinner.stopAndPersist();
164
- return builds;
165
- case generated_1.BuildStatus.InProgress:
166
- spinner.text = 'Build in progress...';
167
- break;
168
- case generated_1.BuildStatus.Errored:
169
- spinner.fail('Build failed');
170
- if (build.error) {
171
- return builds;
172
- }
173
- else {
174
- throw new Error(`Standalone build failed!`);
175
- }
176
- default:
177
- spinner.warn('Unknown status');
178
- throw new Error(`Unknown build status: ${build.status} - aborting!`);
139
+ async function waitForBuildEndAsync({ buildIds, accountName }, {
140
+ // 2 hours (max build time limit) + 10 minutes (possible queue time)
141
+ timeoutSec = 2 * 60 * 60 + 10 * 60, intervalSec = 10, } = {}) {
142
+ const b = `build${buildIds.length > 1 ? 's' : ''}`;
143
+ log_1.default.log(`Waiting for ${b} to complete. You can press Ctrl+C to exit.`);
144
+ const spinner = (0, ora_1.ora)(`Waiting for ${b} to complete.`).start();
145
+ const endTime = new Date().getTime() + timeoutSec * 1000;
146
+ while (new Date().getTime() <= endTime) {
147
+ const builds = await getBuildsSafelyAsync(buildIds);
148
+ const { refetch } = builds.length === 1
149
+ ? await handleSingleBuildProgressAsync({ build: builds[0], accountName }, { spinner })
150
+ : await handleMultipleBuildsProgressAsync({ builds }, { spinner });
151
+ if (!refetch) {
152
+ return builds;
153
+ }
154
+ await (0, promise_1.sleepAsync)(intervalSec * 1000);
155
+ }
156
+ spinner.fail('Timed out');
157
+ throw new Error('Timeout reached! It is taking longer than expected to finish the build, aborting...');
158
+ }
159
+ exports.waitForBuildEndAsync = waitForBuildEndAsync;
160
+ async function getBuildsSafelyAsync(buildIds) {
161
+ const promises = buildIds.map(async (buildId) => {
162
+ try {
163
+ return await BuildQuery_1.BuildQuery.byIdAsync(buildId, { useCache: false });
164
+ }
165
+ catch (err) {
166
+ log_1.default.debug('Failed to fetch the build status', err);
167
+ return null;
168
+ }
169
+ });
170
+ return await Promise.all(promises);
171
+ }
172
+ let queueProgressBarStarted = false;
173
+ const queueProgressBar = new cli_progress_1.default.SingleBar({ format: '|{bar}| {estimatedWaitTime}' }, cli_progress_1.default.Presets.rect);
174
+ async function handleSingleBuildProgressAsync({ build, accountName }, { spinner }) {
175
+ if (build === null) {
176
+ spinner.text = 'Could not fetch the build status. Check your network connection.';
177
+ return { refetch: true };
178
+ }
179
+ if (queueProgressBarStarted && (build === null || build === void 0 ? void 0 : build.status) && build.status !== generated_1.BuildStatus.InQueue) {
180
+ if (build.status === generated_1.BuildStatus.InProgress) {
181
+ queueProgressBar.update(queueProgressBar.getTotal(), {
182
+ estimatedWaitTime: '',
183
+ });
184
+ }
185
+ queueProgressBar.stop();
186
+ log_1.default.newLine();
187
+ queueProgressBarStarted = false;
188
+ spinner.start('Build is about to start');
189
+ }
190
+ switch (build.status) {
191
+ case generated_1.BuildStatus.Finished:
192
+ spinner.succeed('Build finished');
193
+ return { refetch: false };
194
+ case generated_1.BuildStatus.New:
195
+ spinner.text = `Build is waiting to enter the queue. Check your concurrency limit at ${chalk_1.default.underline(formatAccountSubscriptionsUrl(accountName))}.`;
196
+ break;
197
+ case generated_1.BuildStatus.InQueue: {
198
+ spinner.text = 'Build queued...';
199
+ const progressBarPayload = typeof build.estimatedWaitTimeLeftSeconds === 'number'
200
+ ? { estimatedWaitTime: formatEstimatedWaitTime(build.estimatedWaitTimeLeftSeconds) }
201
+ : { estimatedWaitTime: '' };
202
+ if (!queueProgressBarStarted &&
203
+ typeof build.initialQueuePosition === 'number' &&
204
+ typeof build.queuePosition === 'number') {
205
+ spinner.stopAndPersist();
206
+ if (build.priority !== generated_1.BuildPriority.High) {
207
+ log_1.default.newLine();
208
+ log_1.default.log('Start builds sooner in the priority queue.');
209
+ log_1.default.log(`Sign up for EAS Production or Enterprise at ${chalk_1.default.underline(formatAccountSubscriptionsUrl(accountName))}`);
179
210
  }
211
+ log_1.default.newLine();
212
+ log_1.default.log('Waiting in queue');
213
+ queueProgressBar.start(build.initialQueuePosition + 1, build.initialQueuePosition - build.queuePosition + 1, progressBarPayload);
214
+ queueProgressBarStarted = true;
180
215
  }
181
- else {
182
- if (!spinner.text) {
183
- spinner.text = 'Could not fetch the build status. Check your network connection.';
184
- }
216
+ if (typeof build.queuePosition === 'number') {
217
+ queueProgressBar.update(build.queuePosition, progressBarPayload);
185
218
  }
219
+ break;
186
220
  }
187
- else {
188
- if (builds.filter(build => (build === null || build === void 0 ? void 0 : build.status) === generated_1.BuildStatus.Finished).length === builds.length) {
189
- spinner.succeed('All builds have finished');
190
- return builds;
191
- }
192
- else if (builds.filter(build => (build === null || build === void 0 ? void 0 : build.status)
193
- ? [generated_1.BuildStatus.Finished, generated_1.BuildStatus.Errored, generated_1.BuildStatus.Canceled].includes(build.status)
194
- : false).length === builds.length) {
195
- spinner.fail('Some of the builds were canceled or failed.');
196
- return builds;
221
+ case generated_1.BuildStatus.Canceled:
222
+ spinner.fail('Build canceled');
223
+ return { refetch: false };
224
+ case generated_1.BuildStatus.InProgress:
225
+ spinner.text = 'Build in progress...';
226
+ break;
227
+ case generated_1.BuildStatus.Errored:
228
+ spinner.fail('Build failed');
229
+ if (build.error) {
230
+ return { refetch: false };
197
231
  }
198
232
  else {
199
- const newBuilds = builds.filter(build => (build === null || build === void 0 ? void 0 : build.status) === generated_1.BuildStatus.New).length;
200
- const inQueue = builds.filter(build => (build === null || build === void 0 ? void 0 : build.status) === generated_1.BuildStatus.InQueue).length;
201
- const inProgress = builds.filter(build => (build === null || build === void 0 ? void 0 : build.status) === generated_1.BuildStatus.InProgress).length;
202
- const errored = builds.filter(build => (build === null || build === void 0 ? void 0 : build.status) === generated_1.BuildStatus.Errored).length;
203
- const finished = builds.filter(build => (build === null || build === void 0 ? void 0 : build.status) === generated_1.BuildStatus.Finished).length;
204
- const canceled = builds.filter(build => (build === null || build === void 0 ? void 0 : build.status) === generated_1.BuildStatus.Canceled).length;
205
- const unknown = builds.length - newBuilds - inQueue - inProgress - errored - finished - canceled;
206
- spinner.text = [
207
- newBuilds && `Builds created: ${newBuilds}`,
208
- inQueue && `Builds in queue: ${inQueue}`,
209
- inProgress && `Builds in progress: ${inProgress}`,
210
- canceled && `Builds canceled: ${canceled}`,
211
- errored && chalk_1.default.red(`Builds failed: ${errored}`),
212
- finished && chalk_1.default.green(`Builds finished: ${finished}`),
213
- unknown && chalk_1.default.red(`Builds with unknown status: ${unknown}`),
214
- ]
215
- .filter(i => i)
216
- .join('\t');
233
+ throw new Error('Standalone build failed!');
217
234
  }
235
+ default:
236
+ spinner.warn('Unknown status');
237
+ throw new Error(`Unknown build status: ${build.status} - aborting!`);
238
+ }
239
+ return { refetch: true };
240
+ }
241
+ const statusToDisplayName = {
242
+ [generated_1.BuildStatus.New]: 'waiting to enter the queue (concurrency limit reached)',
243
+ [generated_1.BuildStatus.InQueue]: 'in queue',
244
+ [generated_1.BuildStatus.InProgress]: 'in progress',
245
+ [generated_1.BuildStatus.Canceled]: 'canceled',
246
+ [generated_1.BuildStatus.Finished]: 'finished',
247
+ [generated_1.BuildStatus.Errored]: 'failed',
248
+ };
249
+ const platforms = [generated_1.AppPlatform.Android, generated_1.AppPlatform.Ios];
250
+ async function handleMultipleBuildsProgressAsync({ builds: maybeBuilds }, { spinner }) {
251
+ const buildCount = maybeBuilds.length;
252
+ const builds = maybeBuilds.filter(isBuildFragment);
253
+ const allFinished = builds.filter(build => build.status === generated_1.BuildStatus.Finished).length === buildCount;
254
+ const allSettled = builds.filter(build => [generated_1.BuildStatus.Finished, generated_1.BuildStatus.Errored, generated_1.BuildStatus.Canceled].includes(build.status)).length === buildCount;
255
+ if (allSettled) {
256
+ if (allFinished) {
257
+ spinner.succeed(formatSettledBuildsText(builds));
218
258
  }
219
- time = new Date().getTime();
220
- await (0, promise_1.sleepAsync)(intervalSec * 1000);
259
+ else {
260
+ spinner.fail(formatSettledBuildsText(builds));
261
+ }
262
+ return { refetch: false };
263
+ }
264
+ else {
265
+ spinner.text = formatPendingBuildsText(builds);
266
+ return { refetch: true };
221
267
  }
222
- spinner.warn('Timed out');
223
- throw new Error('Timeout reached! It is taking longer than expected to finish the build, aborting...');
224
268
  }
225
- exports.waitForBuildEndAsync = waitForBuildEndAsync;
269
+ function formatSettledBuildsText(builds) {
270
+ return platforms
271
+ .map(platform => {
272
+ const build = (0, nullthrows_1.default)(builds.find(build => build.platform === platform), `Build for platform ${platform} must be defined in this context`);
273
+ return `${platform_1.appPlatformEmojis[platform]} ${platform_1.appPlatformDisplayNames[platform]} build - status: ${chalk_1.default.bold(statusToDisplayName[build.status])}`;
274
+ })
275
+ .join('\n ');
276
+ }
277
+ function formatPendingBuildsText(builds) {
278
+ return platforms
279
+ .map(platform => {
280
+ const build = builds.find(build => build.platform === platform);
281
+ const status = build ? statusToDisplayName[build.status] : 'unknown';
282
+ let extraInfo = '';
283
+ if ((build === null || build === void 0 ? void 0 : build.status) === generated_1.BuildStatus.InQueue &&
284
+ typeof build.initialQueuePosition === 'number' &&
285
+ typeof build.queuePosition === 'number') {
286
+ const percent = Math.floor(((build.initialQueuePosition - build.queuePosition + 1) /
287
+ (build.initialQueuePosition + 1)) *
288
+ 100);
289
+ const estimatedWaitTime = typeof build.estimatedWaitTimeLeftSeconds === 'number'
290
+ ? ` - ${formatEstimatedWaitTime(build.estimatedWaitTimeLeftSeconds)}`
291
+ : '';
292
+ extraInfo = ` - queue progress: ${chalk_1.default.bold(`${percent}%`)}${estimatedWaitTime}`;
293
+ }
294
+ return `${platform_1.appPlatformEmojis[platform]} ${platform_1.appPlatformDisplayNames[platform]} build - status: ${chalk_1.default.bold(status)}${extraInfo}`;
295
+ })
296
+ .join('\n ');
297
+ }
298
+ function isBuildFragment(maybeBuild) {
299
+ return maybeBuild !== null;
300
+ }
301
+ function formatEstimatedWaitTime(estimatedWaitTimeLeftSeconds) {
302
+ if (estimatedWaitTimeLeftSeconds < 5 * 60) {
303
+ return 'starting soon...';
304
+ }
305
+ else {
306
+ const n = Math.floor(estimatedWaitTimeLeftSeconds / (10 * 60)) + 1;
307
+ return `starting in about ${n}0 minutes...`;
308
+ }
309
+ }
310
+ function formatAccountSubscriptionsUrl(accountName) {
311
+ return new URL(`/accounts/${accountName}/settings/subscriptions`, (0, api_1.getExpoWebsiteBaseUrl)()).toString();
312
+ }
@@ -29,7 +29,9 @@ async function createIosContextAsync(ctx) {
29
29
  const targets = await (0, target_1.resolveTargetsAsync)({
30
30
  projectDir: ctx.projectDir,
31
31
  exp: ctx.exp,
32
- }, xcodeBuildContext);
32
+ xcodeBuildContext,
33
+ env: buildProfile.env,
34
+ });
33
35
  const applicationTarget = (0, target_1.findApplicationTarget)(targets);
34
36
  const applicationTargetBuildSettings = resolveBuildSettings(ctx, applicationTarget);
35
37
  return {
@@ -5,20 +5,16 @@ const tslib_1 = require("tslib");
5
5
  const eas_build_job_1 = require("@expo/eas-build-job");
6
6
  const IosCredentialsProvider_1 = tslib_1.__importDefault(require("../../credentials/ios/IosCredentialsProvider"));
7
7
  const BuildCredentialsUtils_1 = require("../../credentials/ios/actions/BuildCredentialsUtils");
8
- const entitlements_1 = require("../../credentials/ios/appstore/entitlements");
9
8
  const credentials_1 = require("../utils/credentials");
10
9
  async function ensureIosCredentialsAsync(buildCtx, targets) {
11
- var _a, _b;
10
+ var _a;
12
11
  if (!shouldProvideCredentials(buildCtx)) {
13
12
  return;
14
13
  }
15
14
  const provider = new IosCredentialsProvider_1.default(buildCtx.credentialsCtx, {
16
15
  app: (0, BuildCredentialsUtils_1.getAppFromContext)(buildCtx.credentialsCtx),
17
16
  targets,
18
- iosCapabilitiesOptions: {
19
- entitlements: await (0, entitlements_1.resolveEntitlementsJsonAsync)(buildCtx.projectDir, buildCtx.workflow, (_a = buildCtx.buildProfile.env) !== null && _a !== void 0 ? _a : {}),
20
- },
21
- distribution: (_b = buildCtx.buildProfile.distribution) !== null && _b !== void 0 ? _b : 'store',
17
+ distribution: (_a = buildCtx.buildProfile.distribution) !== null && _a !== void 0 ? _a : 'store',
22
18
  enterpriseProvisioning: buildCtx.buildProfile.enterpriseProvisioning,
23
19
  });
24
20
  const { credentialsSource } = buildCtx.buildProfile;
@@ -6,7 +6,7 @@ const spawn_async_1 = tslib_1.__importDefault(require("@expo/spawn-async"));
6
6
  const semver_1 = tslib_1.__importDefault(require("semver"));
7
7
  const ora_1 = require("../ora");
8
8
  const PLUGIN_PACKAGE_NAME = 'eas-cli-local-build-plugin';
9
- const PLUGIN_PACKAGE_VERSION = '0.0.74';
9
+ const PLUGIN_PACKAGE_VERSION = '0.0.78';
10
10
  async function runLocalBuildAsync(job, options) {
11
11
  var _a;
12
12
  const { command, args } = await getCommandAndArgsAsync(job);
@@ -98,7 +98,11 @@ async function runBuildAndSubmitAsync(projectDir, flags) {
98
98
  }
99
99
  return;
100
100
  }
101
- const builds = await (0, build_2.waitForBuildEndAsync)(startedBuilds.map(({ build }) => build.id));
101
+ const { accountName } = Object.values(buildCtxByPlatform)[0];
102
+ const builds = await (0, build_2.waitForBuildEndAsync)({
103
+ buildIds: startedBuilds.map(({ build }) => build.id),
104
+ accountName,
105
+ });
102
106
  (0, printBuildInfo_1.printBuildResults)(builds, flags.json);
103
107
  const haveAllBuildsFailedOrCanceled = builds.every(build => (build === null || build === void 0 ? void 0 : build.status) && [generated_1.BuildStatus.Errored, generated_1.BuildStatus.Canceled].includes(build === null || build === void 0 ? void 0 : build.status));
104
108
  if (haveAllBuildsFailedOrCanceled || !flags.autoSubmit) {
@@ -14,6 +14,7 @@ export default class UpdatePublish extends EasCommand {
14
14
  json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
15
15
  auto: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
16
16
  'private-key-path': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined>;
17
+ 'non-interactive': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
17
18
  };
18
19
  runAsync(): Promise<void>;
19
20
  }
@@ -89,7 +89,7 @@ async function ensureBranchExistsAsync({ appId, name: branchName, }) {
89
89
  class UpdatePublish extends EasCommand_1.default {
90
90
  async runAsync() {
91
91
  var _a, _b, _c;
92
- let { flags: { branch: branchName, json: jsonFlag, auto: autoFlag, message, republish, group, 'input-dir': inputDir, 'skip-bundler': skipBundler, platform, 'private-key-path': privateKeyPath, }, } = await this.parse(UpdatePublish);
92
+ let { flags: { branch: branchName, json: jsonFlag, auto: autoFlag, message, republish, group, 'input-dir': inputDir, 'skip-bundler': skipBundler, platform, 'private-key-path': privateKeyPath, 'non-interactive': nonInteractive, }, } = await this.parse(UpdatePublish);
93
93
  if (jsonFlag) {
94
94
  (0, json_1.enableJsonOutput)();
95
95
  }
@@ -101,8 +101,16 @@ class UpdatePublish extends EasCommand_1.default {
101
101
  skipSDKVersionRequirement: true,
102
102
  isPublicConfig: true,
103
103
  });
104
- const codeSigningInfo = await (0, code_signing_1.getCodeSigningInfoAsync)(exp, privateKeyPath);
105
- if (!(0, projectUtils_1.isExpoUpdatesInstalledOrAvailable)(projectDir, exp.sdkVersion)) {
104
+ const { exp: expPrivate } = (0, config_1.getConfig)(projectDir, {
105
+ skipSDKVersionRequirement: true,
106
+ isPublicConfig: false,
107
+ });
108
+ const codeSigningInfo = await (0, code_signing_1.getCodeSigningInfoAsync)(expPrivate, privateKeyPath);
109
+ const hasExpoUpdates = (0, projectUtils_1.isExpoUpdatesInstalledOrAvailable)(projectDir, exp.sdkVersion);
110
+ if (!hasExpoUpdates && nonInteractive) {
111
+ core_1.Errors.error(`${chalk_1.default.bold('expo-updates')} must already be installed when executing in non-interactive mode`, { exit: 1 });
112
+ }
113
+ if (!hasExpoUpdates) {
106
114
  const install = await (0, prompts_1.confirmAsync)({
107
115
  message: `You are creating an update which requires ${chalk_1.default.bold('expo-updates')} to be installed in your app.\n Do you want EAS CLI to install it for you?`,
108
116
  instructions: 'The command will abort unless you agree.',
@@ -125,6 +133,9 @@ class UpdatePublish extends EasCommand_1.default {
125
133
  `branch-${Math.random().toString(36).substr(2, 4)}`;
126
134
  }
127
135
  if (!branchName) {
136
+ if (nonInteractive) {
137
+ throw new Error('Must supply --branch or use --auto when in non-interactive mode');
138
+ }
128
139
  const validationMessage = 'Branch name may not be empty.';
129
140
  if (jsonFlag) {
130
141
  throw new Error(validationMessage);
@@ -164,6 +175,9 @@ class UpdatePublish extends EasCommand_1.default {
164
175
  updatesToRepublish = await getUpdateGroupAsync({ group });
165
176
  }
166
177
  else {
178
+ if (nonInteractive) {
179
+ throw new Error('Must supply --group when in non-interactive mode');
180
+ }
167
181
  // Drop into interactive mode if the user has not specified an update group to republish.
168
182
  if (jsonFlag) {
169
183
  throw new Error('You must specify the update group to republish.');
@@ -212,6 +226,9 @@ class UpdatePublish extends EasCommand_1.default {
212
226
  oldMessage = (_a = updatesToRepublishFilteredByPlatform[0].message) !== null && _a !== void 0 ? _a : '';
213
227
  oldRuntimeVersion = updatesToRepublishFilteredByPlatform[0].runtimeVersion;
214
228
  if (!message) {
229
+ if (nonInteractive) {
230
+ throw new Error('Must supply --message when in non-interactive mode');
231
+ }
215
232
  const validationMessage = 'publish message may not be empty.';
216
233
  if (jsonFlag) {
217
234
  throw new Error(validationMessage);
@@ -230,6 +247,9 @@ class UpdatePublish extends EasCommand_1.default {
230
247
  message = (_b = (await (0, vcs_1.getVcsClient)().getLastCommitMessageAsync())) === null || _b === void 0 ? void 0 : _b.trim();
231
248
  }
232
249
  if (!message) {
250
+ if (nonInteractive) {
251
+ throw new Error('Must supply --message or use --auto when in non-interactive mode');
252
+ }
233
253
  const validationMessage = 'publish message may not be empty.';
234
254
  if (jsonFlag) {
235
255
  throw new Error(validationMessage);
@@ -402,6 +422,10 @@ UpdatePublish.flags = {
402
422
  description: `File containing the PEM-encoded private key corresponding to the certificate in expo-updates' configuration. Defaults to a file named "private-key.pem" in the certificate's directory.`,
403
423
  required: false,
404
424
  }),
425
+ 'non-interactive': core_1.Flags.boolean({
426
+ default: false,
427
+ description: 'Run command in non-interactive mode',
428
+ }),
405
429
  };
406
430
  async function getRuntimeVersionObjectAsync(exp, platformFlag, projectDir) {
407
431
  var _a, _b;
@@ -2,7 +2,9 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CreateGoogleServiceAccountKey = void 0;
4
4
  const tslib_1 = require("tslib");
5
- const log_1 = tslib_1.__importDefault(require("../../../log"));
5
+ const chalk_1 = tslib_1.__importDefault(require("chalk"));
6
+ const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
7
+ const log_1 = tslib_1.__importStar(require("../../../log"));
6
8
  const prompts_1 = require("../../../prompts");
7
9
  const googleServiceAccountKey_1 = require("../utils/googleServiceAccountKey");
8
10
  class CreateGoogleServiceAccountKey {
@@ -33,15 +35,28 @@ class CreateGoogleServiceAccountKey {
33
35
  if (detectedPath) {
34
36
  return detectedPath;
35
37
  }
36
- const { keyJsonPath } = await (0, prompts_1.promptAsync)([
37
- {
38
- type: 'text',
39
- name: 'keyJsonPath',
40
- message: 'Path to Google Service Account Key JSON file:',
41
- validate: (value) => value.length > 0 || "Path can't be empty",
38
+ log_1.default.log(`${chalk_1.default.bold('A Google Service Account JSON key is required to upload your app to Google Play Store')}.\n` +
39
+ `If you're not sure what this is or how to create one, ${(0, log_1.learnMore)('https://expo.fyi/creating-google-service-account', { learnMoreMessage: 'learn more' })}`);
40
+ const { filePath } = await (0, prompts_1.promptAsync)({
41
+ name: 'filePath',
42
+ message: 'Path to Google Service Account file:',
43
+ initial: 'api-0000000000000000000-111111-aaaaaabbbbbb.json',
44
+ type: 'text',
45
+ // eslint-disable-next-line async-protect/async-suffix
46
+ validate: async (filePath) => {
47
+ try {
48
+ const stats = await fs_extra_1.default.stat(filePath);
49
+ if (stats.isFile()) {
50
+ return true;
51
+ }
52
+ return 'Input is not a file.';
53
+ }
54
+ catch {
55
+ return 'File does not exist.';
56
+ }
42
57
  },
43
- ]);
44
- return keyJsonPath;
58
+ });
59
+ return filePath;
45
60
  }
46
61
  }
47
62
  exports.CreateGoogleServiceAccountKey = CreateGoogleServiceAccountKey;
@@ -12,6 +12,7 @@ const User_1 = require("../user/User");
12
12
  const AndroidGraphqlClient = tslib_1.__importStar(require("./android/api/GraphqlClient"));
13
13
  const IosGraphqlClient = tslib_1.__importStar(require("./ios/api/GraphqlClient"));
14
14
  const AppStoreApi_1 = tslib_1.__importDefault(require("./ios/appstore/AppStoreApi"));
15
+ const authenticateTypes_1 = require("./ios/appstore/authenticateTypes");
15
16
  class CredentialsContext {
16
17
  constructor(options) {
17
18
  var _a, _b;
@@ -73,6 +74,10 @@ class CredentialsContext {
73
74
  if (this.nonInteractive) {
74
75
  return;
75
76
  }
77
+ if (this.appStore.defaultAuthenticationMode === authenticateTypes_1.AuthenticationMode.API_KEY) {
78
+ await this.appStore.ensureAuthenticatedAsync();
79
+ return;
80
+ }
76
81
  log_1.default.log(chalk_1.default.green('If you provide your Apple account credentials we will be able to generate all necessary build credentials and fully validate them.'));
77
82
  log_1.default.log(chalk_1.default.green('This is optional, but without Apple account access you will need to provide all the missing values manually and we can only run minimal validation on them.'));
78
83
  const confirm = await (0, prompts_1.confirmAsync)({
@@ -1,14 +1,12 @@
1
1
  import { Platform } from '@expo/eas-build-job';
2
2
  import { CredentialsSource, DistributionType, IosEnterpriseProvisioning } from '@expo/eas-json';
3
3
  import { CredentialsContext } from '../context';
4
- import { IosCapabilitiesOptions } from './appstore/ensureAppExists';
5
4
  import { App, IosCredentials, Target } from './types';
6
5
  interface Options {
7
6
  app: App;
8
7
  targets: Target[];
9
8
  distribution: DistributionType;
10
9
  enterpriseProvisioning?: IosEnterpriseProvisioning;
11
- iosCapabilitiesOptions?: IosCapabilitiesOptions;
12
10
  }
13
11
  export default class IosCredentialsProvider {
14
12
  private ctx;
@@ -44,7 +44,6 @@ class IosCredentialsProvider {
44
44
  targets: this.options.targets,
45
45
  distribution: this.options.distribution,
46
46
  enterpriseProvisioning: this.options.enterpriseProvisioning,
47
- iosCapabilitiesOptions: this.options.iosCapabilitiesOptions,
48
47
  }).runAsync(this.ctx);
49
48
  }
50
49
  async getPushKeyAsync(ctx, targets) {
@@ -70,7 +70,6 @@ async function provideOrGenerateAscApiKeyAsync(ctx, purpose) {
70
70
  }
71
71
  exports.provideOrGenerateAscApiKeyAsync = provideOrGenerateAscApiKeyAsync;
72
72
  async function generateAscApiKeyAsync(ctx, purpose) {
73
- //console.log('debug');
74
73
  await ctx.appStore.ensureAuthenticatedAsync();
75
74
  const ascApiKey = await ctx.appStore.createAscApiKeyAsync({
76
75
  nickname: getAscApiKeyName(purpose),
@@ -46,7 +46,7 @@ class ConfigureProvisioningProfile {
46
46
  certP12: certificateP12,
47
47
  certPassword: certificatePassword,
48
48
  distCertSerialNumber: serialNumber,
49
- teamId: authCtx.appleId,
49
+ teamId: authCtx.team.id,
50
50
  });
51
51
  const bundleIdTag = `(${app.bundleIdentifier})`;
52
52
  const slugTag = `@${app.account.name}/${app.projectName}`;
@@ -45,7 +45,7 @@ class CreateProvisioningProfile {
45
45
  certP12: this.distributionCertificate.certificateP12,
46
46
  certPassword: this.distributionCertificate.certificatePassword,
47
47
  distCertSerialNumber: this.distributionCertificate.serialNumber,
48
- teamId: (_c = (_b = this.distributionCertificate.appleTeam) === null || _b === void 0 ? void 0 : _b.appleTeamIdentifier) !== null && _c !== void 0 ? _c : appleAuthCtx.appleId,
48
+ teamId: (_c = (_b = this.distributionCertificate.appleTeam) === null || _b === void 0 ? void 0 : _b.appleTeamIdentifier) !== null && _c !== void 0 ? _c : appleAuthCtx.team.id,
49
49
  });
50
50
  }
51
51
  }
@@ -1,13 +1,11 @@
1
1
  import { DistributionType, IosEnterpriseProvisioning } from '@expo/eas-json';
2
2
  import { CredentialsContext } from '../../context';
3
- import { IosCapabilitiesOptions } from '../appstore/ensureAppExists';
4
3
  import { App, IosCredentials, Target } from '../types';
5
4
  interface Options {
6
5
  app: App;
7
6
  targets: Target[];
8
7
  distribution: DistributionType;
9
8
  enterpriseProvisioning?: IosEnterpriseProvisioning;
10
- iosCapabilitiesOptions?: IosCapabilitiesOptions;
11
9
  }
12
10
  export declare class SetUpBuildCredentials {
13
11
  private options;