eas-cli 18.2.0 → 18.4.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.
@@ -281,6 +281,8 @@ async function getBuildsSafelyAsync(graphqlClient, buildIds) {
281
281
  }
282
282
  let queueProgressBarStarted = false;
283
283
  const queueProgressBar = new cli_progress_1.default.SingleBar({ format: '|{bar}| {estimatedWaitTime}' }, cli_progress_1.default.Presets.rect);
284
+ let statusNewSetAt = null;
285
+ const NEW_STATUS_GRACE_PERIOD_MS = 15_000;
284
286
  async function handleSingleBuildProgressAsync({ build, accountName, }, { spinner }) {
285
287
  if (build === null) {
286
288
  spinner.text = 'Could not fetch the build status. Check your network connection.';
@@ -301,9 +303,18 @@ async function handleSingleBuildProgressAsync({ build, accountName, }, { spinner
301
303
  case generated_1.BuildStatus.Finished:
302
304
  spinner.succeed('Build finished');
303
305
  return { refetch: false };
304
- case generated_1.BuildStatus.New:
305
- spinner.text = `Build concurrency limit reached for your account. Build will enter queue once a concurrency becomes available. Add additional concurrencies at ${(0, log_1.link)(formatAccountBillingUrl(accountName))}.`;
306
+ case generated_1.BuildStatus.New: {
307
+ const now = Date.now();
308
+ statusNewSetAt ??= now;
309
+ const newStatusDurationMs = now - statusNewSetAt;
310
+ if (newStatusDurationMs < NEW_STATUS_GRACE_PERIOD_MS) {
311
+ spinner.text = 'Waiting for build to get enqueued…';
312
+ }
313
+ else {
314
+ spinner.text = `Build concurrency limit reached for your account. Build will enter queue once a concurrency becomes available. Add additional concurrencies at ${(0, log_1.link)(formatAccountBillingUrl(accountName))}.`;
315
+ }
306
316
  break;
317
+ }
307
318
  case generated_1.BuildStatus.InQueue: {
308
319
  spinner.text = 'Build queued...';
309
320
  const progressBarPayload = typeof build.estimatedWaitTimeLeftSeconds === 'number'
@@ -356,7 +367,7 @@ const priorityToQueueDisplayName = {
356
367
  [generated_1.BuildPriority.High]: 'priority queue',
357
368
  };
358
369
  const statusToDisplayName = {
359
- [generated_1.BuildStatus.New]: 'waiting to enter the queue (concurrency limit reached)',
370
+ [generated_1.BuildStatus.New]: 'waiting to enter the queue',
360
371
  [generated_1.BuildStatus.InQueue]: 'in queue',
361
372
  [generated_1.BuildStatus.InProgress]: 'in progress',
362
373
  [generated_1.BuildStatus.PendingCancel]: 'canceled',
@@ -368,6 +379,7 @@ const platforms = [generated_1.AppPlatform.Android, generated_1.AppPlatform.Ios]
368
379
  async function handleMultipleBuildsProgressAsync({ builds: maybeBuilds }, { spinner, originalSpinnerText }) {
369
380
  const buildCount = maybeBuilds.length;
370
381
  const builds = maybeBuilds.filter(isBuildFragment);
382
+ const someNew = builds.some(build => build.status === generated_1.BuildStatus.New);
371
383
  const allFinished = builds.filter(build => build.status === generated_1.BuildStatus.Finished).length === buildCount;
372
384
  const allSettled = builds.filter(build => [
373
385
  generated_1.BuildStatus.Finished,
@@ -375,6 +387,9 @@ async function handleMultipleBuildsProgressAsync({ builds: maybeBuilds }, { spin
375
387
  generated_1.BuildStatus.Canceled,
376
388
  generated_1.BuildStatus.PendingCancel,
377
389
  ].includes(build.status)).length === buildCount;
390
+ if (someNew && statusNewSetAt === null) {
391
+ statusNewSetAt = Date.now();
392
+ }
378
393
  if (allSettled) {
379
394
  if (allFinished) {
380
395
  spinner.succeed(formatSettledBuildsText(builds));
@@ -385,7 +400,10 @@ async function handleMultipleBuildsProgressAsync({ builds: maybeBuilds }, { spin
385
400
  return { refetch: false };
386
401
  }
387
402
  else {
388
- spinner.text = formatPendingBuildsText(originalSpinnerText, builds);
403
+ const showConcurrencyWarning = someNew &&
404
+ statusNewSetAt !== null &&
405
+ Date.now() - statusNewSetAt >= NEW_STATUS_GRACE_PERIOD_MS;
406
+ spinner.text = formatPendingBuildsText(originalSpinnerText, builds, showConcurrencyWarning);
389
407
  return { refetch: true };
390
408
  }
391
409
  }
@@ -397,12 +415,15 @@ function formatSettledBuildsText(builds) {
397
415
  })
398
416
  .join('\n ');
399
417
  }
400
- function formatPendingBuildsText(originalSpinnerText, builds) {
418
+ function formatPendingBuildsText(originalSpinnerText, builds, showConcurrencyWarning) {
401
419
  return [
402
420
  originalSpinnerText,
403
421
  ...platforms.map(platform => {
404
422
  const build = builds.find(build => build.platform === platform);
405
423
  const status = build ? statusToDisplayName[build.status] : 'unknown';
424
+ const concurrencyWarning = showConcurrencyWarning && build?.status === generated_1.BuildStatus.New
425
+ ? ' (concurrency limit reached)'
426
+ : '';
406
427
  let extraInfo = '';
407
428
  if (build?.status === generated_1.BuildStatus.InQueue &&
408
429
  typeof build.initialQueuePosition === 'number' &&
@@ -415,7 +436,7 @@ function formatPendingBuildsText(originalSpinnerText, builds) {
415
436
  : '';
416
437
  extraInfo = ` - queue progress: ${chalk_1.default.bold(`${percent}%`)}${estimatedWaitTime}`;
417
438
  }
418
- return `${platform_1.appPlatformEmojis[platform]} ${platform_1.appPlatformDisplayNames[platform]} build - status: ${chalk_1.default.bold(status)}${extraInfo}`;
439
+ return `${platform_1.appPlatformEmojis[platform]} ${platform_1.appPlatformDisplayNames[platform]} build - status: ${chalk_1.default.bold(status)}${concurrencyWarning}${extraInfo}`;
419
440
  }),
420
441
  ].join('\n ');
421
442
  }
@@ -1,3 +1,4 @@
1
+ export declare function isNonInteractiveByDefault(): boolean;
1
2
  export declare const EasNonInteractiveAndJsonFlags: {
2
3
  json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
3
4
  'non-interactive': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
@@ -1,14 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.EasUpdateEnvironmentRequiredFlag = exports.EasUpdateEnvironmentFlag = exports.EasJsonOnlyFlag = exports.EASNonInteractiveFlag = exports.EASEnvironmentVariableScopeFlag = exports.EASVariableVisibilityFlag = exports.EASVariableFormatFlag = exports.EASMultiEnvironmentFlag = exports.EASEnvironmentFlag = exports.EasEnvironmentFlagParameters = exports.EasNonInteractiveAndJsonFlags = void 0;
4
+ exports.isNonInteractiveByDefault = isNonInteractiveByDefault;
4
5
  exports.resolveNonInteractiveAndJsonFlags = resolveNonInteractiveAndJsonFlags;
5
6
  const core_1 = require("@oclif/core");
7
+ const getenv_1 = require("getenv");
8
+ function isNonInteractiveByDefault() {
9
+ return (0, getenv_1.boolish)('CI', false) || !process.stdin.isTTY;
10
+ }
6
11
  exports.EasNonInteractiveAndJsonFlags = {
7
12
  json: core_1.Flags.boolean({
8
13
  description: 'Enable JSON output, non-JSON messages will be printed to stderr. Implies --non-interactive.',
9
14
  }),
10
15
  'non-interactive': core_1.Flags.boolean({
11
16
  description: 'Run the command in non-interactive mode.',
17
+ default: () => Promise.resolve(isNonInteractiveByDefault()),
18
+ noCacheDefault: true,
12
19
  }),
13
20
  };
14
21
  function resolveNonInteractiveAndJsonFlags(flags) {
@@ -53,6 +60,11 @@ exports.EASEnvironmentVariableScopeFlag = {
53
60
  exports.EASNonInteractiveFlag = {
54
61
  'non-interactive': core_1.Flags.boolean({
55
62
  description: 'Run the command in non-interactive mode.',
63
+ // eslint-disable-next-line async-protect/async-suffix
64
+ default: async () => {
65
+ return isNonInteractiveByDefault();
66
+ },
67
+ noCacheDefault: true,
56
68
  }),
57
69
  };
58
70
  exports.EasJsonOnlyFlag = {
@@ -16,10 +16,14 @@ class AccountView extends EasCommand_1.default {
16
16
  async runAsync() {
17
17
  const { maybeLoggedIn: { actor, authenticationInfo }, } = await this.getContextAsync(AccountView, { nonInteractive: true });
18
18
  if (actor) {
19
+ const displayName = (0, User_1.getActorDisplayName)(actor);
19
20
  const loggedInAs = authenticationInfo.accessToken
20
- ? `${(0, User_1.getActorDisplayName)(actor)} (authenticated using EXPO_TOKEN)`
21
- : (0, User_1.getActorDisplayName)(actor);
21
+ ? `${displayName} (authenticated using EXPO_TOKEN)`
22
+ : displayName;
22
23
  log_1.default.log(chalk_1.default.green(loggedInAs));
24
+ if ('email' in actor) {
25
+ log_1.default.log(actor.email);
26
+ }
23
27
  // personal account is included, only show if more accounts that personal account
24
28
  // but do show personal account in list if there are more
25
29
  const accountExcludingPersonalAccount = actor.accounts.filter(account => !('username' in actor) || account.name !== actor.username);
@@ -6,6 +6,7 @@ export default class BuildDev extends EasCommand {
6
6
  static flags: {
7
7
  platform: import("@oclif/core/lib/interfaces").OptionFlag<Platform | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
8
8
  profile: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
9
+ 'skip-build-if-not-found': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
9
10
  };
10
11
  static contextDefinition: {
11
12
  projectId: import("../../commandUtils/context/ProjectIdContextField").ProjectIdContextField;
@@ -34,6 +34,10 @@ class BuildDev extends EasCommand_1.default {
34
34
  description: `Name of the build profile from eas.json. It must be a profile allowing to create emulator/simulator internal distribution dev client builds. The "${DEFAULT_EAS_BUILD_RUN_PROFILE_NAME}" build profile will be selected by default.`,
35
35
  helpValue: 'PROFILE_NAME',
36
36
  }),
37
+ 'skip-build-if-not-found': core_1.Flags.boolean({
38
+ description: 'Skip build if no successful build with matching fingerprint is found.',
39
+ default: false,
40
+ }),
37
41
  };
38
42
  static contextDefinition = {
39
43
  ...this.ContextOptions.LoggedIn,
@@ -100,9 +104,13 @@ class BuildDev extends EasCommand_1.default {
100
104
  return;
101
105
  }
102
106
  else {
103
- log_1.default.warn('Artifacts for this build expired. New build will be started.');
107
+ log_1.default.warn('Artifacts for this build expired.');
104
108
  }
105
109
  }
110
+ if (flags['skip-build-if-not-found']) {
111
+ log_1.default.log('No successful build with matching fingerprint found. Skipping build.');
112
+ return;
113
+ }
106
114
  log_1.default.log('🚀 No successful build with matching fingerprint found. Starting a new build...');
107
115
  const previousBuildsForSelectedProfile = await this.getBuildsAsync({
108
116
  graphqlClient,
@@ -15915,6 +15915,7 @@ export type CurrentUserQuery = {
15915
15915
  }>;
15916
15916
  } | {
15917
15917
  __typename: 'User';
15918
+ email: string;
15918
15919
  username: string;
15919
15920
  id: string;
15920
15921
  featureGates: any;
@@ -14,6 +14,9 @@ exports.UserQuery = {
14
14
  meActor {
15
15
  __typename
16
16
  id
17
+ ... on User {
18
+ email
19
+ }
17
20
  ... on UserActor {
18
21
  username
19
22
  primaryAccount {