eas-cli 3.15.1 → 3.17.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 (36) hide show
  1. package/README.md +55 -55
  2. package/build/api.d.ts +0 -1
  3. package/build/api.js +1 -14
  4. package/build/build/build.js +4 -0
  5. package/build/build/errors.d.ts +2 -0
  6. package/build/build/errors.js +4 -1
  7. package/build/channel/branch-mapping.d.ts +27 -0
  8. package/build/channel/branch-mapping.js +49 -0
  9. package/build/channel/utils.d.ts +1 -11
  10. package/build/channel/utils.js +10 -3
  11. package/build/commandUtils/EasCommand.js +6 -2
  12. package/build/commandUtils/context/contextUtils/createGraphqlClient.d.ts +2 -2
  13. package/build/commandUtils/context/contextUtils/createGraphqlClient.js +0 -1
  14. package/build/commands/channel/rollout.js +6 -1
  15. package/build/credentials/android/api/graphql/mutations/AndroidAppBuildCredentialsMutation.js +2 -2
  16. package/build/graphql/generated.d.ts +91 -4
  17. package/build/graphql/generated.js +2 -0
  18. package/build/graphql/types/Submission.js +1 -0
  19. package/build/project/ios/entitlements.js +2 -0
  20. package/build/project/workflow.d.ts +1 -0
  21. package/build/project/workflow.js +13 -1
  22. package/build/rollout/utils.d.ts +53 -0
  23. package/build/rollout/utils.js +105 -0
  24. package/build/submit/android/AndroidSubmitCommand.d.ts +1 -0
  25. package/build/submit/android/AndroidSubmitCommand.js +7 -1
  26. package/build/submit/android/AndroidSubmitter.d.ts +1 -1
  27. package/build/submit/android/AndroidSubmitter.js +5 -2
  28. package/build/user/expoSsoLauncher.d.ts +1 -2
  29. package/build/user/expoSsoLauncher.js +40 -12
  30. package/build/user/fetchSessionSecretAndSsoUser.js +2 -4
  31. package/build/utils/expodash/capitalize.d.ts +1 -1
  32. package/build/utils/expodash/capitalize.js +3 -3
  33. package/oclif.manifest.json +1 -1
  34. package/package.json +8 -8
  35. package/build/utils/port.d.ts +0 -2
  36. package/build/utils/port.js +0 -14
@@ -1,15 +1,5 @@
1
1
  import { UpdateChannelObject } from '../graphql/queries/ChannelQuery';
2
- export type BranchMapping = {
3
- version: number;
4
- data: {
5
- branchId: string;
6
- branchMappingLogic: {
7
- operand: number;
8
- clientKey: string;
9
- branchMappingOperator: string;
10
- } & string;
11
- }[];
12
- };
2
+ import { BranchMapping } from './branch-mapping';
13
3
  /**
14
4
  * Get the branch mapping and determine whether it is a rollout.
15
5
  * Ensure that the branch mapping is properly formatted.
@@ -6,6 +6,7 @@ const assert_1 = tslib_1.__importDefault(require("assert"));
6
6
  const chalk_1 = tslib_1.__importDefault(require("chalk"));
7
7
  const log_1 = tslib_1.__importDefault(require("../log"));
8
8
  const utils_1 = require("../update/utils");
9
+ const branch_mapping_1 = require("./branch-mapping");
9
10
  /**
10
11
  * Get the branch mapping and determine whether it is a rollout.
11
12
  * Ensure that the branch mapping is properly formatted.
@@ -27,7 +28,12 @@ function getBranchMapping(branchMappingString) {
27
28
  throw new Error('Branch mapping must be version 0.');
28
29
  }
29
30
  const isRollout = branchMapping.data.length === 2;
30
- const rolloutPercent = (_a = branchMapping.data[0]) === null || _a === void 0 ? void 0 : _a.branchMappingLogic.operand;
31
+ const branchMappingNode = (_a = branchMapping.data[0]) === null || _a === void 0 ? void 0 : _a.branchMappingLogic;
32
+ let rolloutPercent;
33
+ if ((0, branch_mapping_1.isNodeObject)(branchMappingNode)) {
34
+ (0, branch_mapping_1.assertNumber)(branchMappingNode.operand);
35
+ rolloutPercent = branchMappingNode.operand;
36
+ }
31
37
  switch (branchMapping.data.length) {
32
38
  case 0:
33
39
  break;
@@ -37,10 +43,11 @@ function getBranchMapping(branchMappingString) {
37
43
  }
38
44
  break;
39
45
  case 2:
40
- if (branchMapping.data[0].branchMappingLogic.clientKey !== 'rolloutToken') {
46
+ (0, branch_mapping_1.assertNodeObject)(branchMappingNode);
47
+ if (branchMappingNode.clientKey !== 'rolloutToken') {
41
48
  throw new Error('Client key of initial branch mapping must be "rolloutToken"');
42
49
  }
43
- if (branchMapping.data[0].branchMappingLogic.branchMappingOperator !== 'hash_lt') {
50
+ if (branchMappingNode.branchMappingOperator !== 'hash_lt') {
44
51
  throw new Error('Branch mapping operator of initial branch mapping must be "hash_lt"');
45
52
  }
46
53
  if (rolloutPercent == null) {
@@ -69,12 +69,16 @@ class EasCommand extends core_1.Command {
69
69
  }
70
70
  else if (err instanceof core_2.CombinedError && (err === null || err === void 0 ? void 0 : err.graphQLErrors)) {
71
71
  const cleanMessage = err === null || err === void 0 ? void 0 : err.graphQLErrors.map((graphQLError) => {
72
- var _a;
72
+ var _a, _b;
73
73
  const messageLine = graphQLError.message.replace('[GraphQL] ', '');
74
74
  const requestIdLine = ((_a = graphQLError.extensions) === null || _a === void 0 ? void 0 : _a.requestId)
75
75
  ? `\nRequest ID: ${err.graphQLErrors[0].extensions.requestId}`
76
76
  : '';
77
- return `${messageLine}${requestIdLine}`;
77
+ const defaultMsg = `${messageLine}${requestIdLine}`;
78
+ if (((_b = graphQLError.extensions) === null || _b === void 0 ? void 0 : _b.errorCode) === 'UNAUTHORIZED_ERROR') {
79
+ return `You don't have the required permissions to perform this operation.\n\n${defaultMsg}`;
80
+ }
81
+ return defaultMsg;
78
82
  }).join('\n');
79
83
  log_1.default.error(cleanMessage);
80
84
  baseMessage = BASE_GRAPHQL_ERROR_MESSAGE;
@@ -1,9 +1,9 @@
1
- import { AnyVariables, Client, OperationContext, OperationResult, PromisifiedSource, TypedDocumentNode } from '@urql/core';
1
+ import { AnyVariables, Client, OperationContext, OperationResult, OperationResultSource, TypedDocumentNode } from '@urql/core';
2
2
  import { DocumentNode } from 'graphql';
3
3
  export interface ExpoGraphqlClient extends Client {
4
4
  query<Data = any, Variables extends AnyVariables = AnyVariables>(query: DocumentNode | TypedDocumentNode<Data, Variables> | string, variables: Variables, context: Partial<OperationContext> & {
5
5
  additionalTypenames: string[];
6
- }): PromisifiedSource<OperationResult<Data, Variables>>;
6
+ }): OperationResultSource<OperationResult<Data, Variables>>;
7
7
  }
8
8
  export declare function createGraphqlClient(authInfo: {
9
9
  accessToken: string | null;
@@ -11,7 +11,6 @@ function createGraphqlClient(authInfo) {
11
11
  return (0, core_1.createClient)({
12
12
  url: (0, api_1.getExpoApiBaseUrl)() + '/graphql',
13
13
  exchanges: [
14
- core_1.dedupExchange,
15
14
  core_1.cacheExchange,
16
15
  (0, exchange_retry_1.retryExchange)({
17
16
  maxDelayMs: 4000,
@@ -5,6 +5,7 @@ const tslib_1 = require("tslib");
5
5
  const core_1 = require("@oclif/core");
6
6
  const chalk_1 = tslib_1.__importDefault(require("chalk"));
7
7
  const queries_1 = require("../../branch/queries");
8
+ const branch_mapping_1 = require("../../channel/branch-mapping");
8
9
  const queries_2 = require("../../channel/queries");
9
10
  const utils_1 = require("../../channel/utils");
10
11
  const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasCommand"));
@@ -35,6 +36,7 @@ async function promptForRolloutPercentAsync({ promptMessage, }) {
35
36
  return rolloutPercent;
36
37
  }
37
38
  function getRolloutInfo(channel) {
39
+ var _b;
38
40
  const { branchMapping } = (0, utils_1.getBranchMapping)(channel.branchMapping);
39
41
  const [newBranchId, oldBranchId] = branchMapping.data.map(d => d.branchId);
40
42
  const newBranch = channel.updateBranches.filter(branch => branch.id === newBranchId)[0];
@@ -42,7 +44,10 @@ function getRolloutInfo(channel) {
42
44
  if (!newBranch || !oldBranch) {
43
45
  throw new Error(`Branch mapping rollout is missing a branch for channel "${channel.name}".`);
44
46
  }
45
- const currentPercent = 100 * branchMapping.data[0].branchMappingLogic.operand;
47
+ const branchMappingNode = (_b = branchMapping.data[0]) === null || _b === void 0 ? void 0 : _b.branchMappingLogic;
48
+ (0, branch_mapping_1.assertNodeObject)(branchMappingNode);
49
+ (0, branch_mapping_1.assertNumber)(branchMappingNode.operand);
50
+ const currentPercent = 100 * branchMappingNode.operand;
46
51
  return { newBranch, oldBranch, currentPercent };
47
52
  }
48
53
  async function startRolloutAsync(graphqlClient, { channelName, branchName, percent, projectId, displayName, currentBranchMapping, channel, nonInteractive, }) {
@@ -37,7 +37,7 @@ exports.AndroidAppBuildCredentialsMutation = {
37
37
  async setDefaultAndroidAppBuildCredentialsAsync(graphqlClient, androidAppBuildCredentialsId) {
38
38
  const data = await (0, client_1.withErrorHandlingAsync)(graphqlClient
39
39
  .mutation((0, graphql_tag_1.default) `
40
- mutation AndroidAppBuildCredentialsMutation(
40
+ mutation SetDefaultAndroidAppBuildCredentialsMutation(
41
41
  $androidAppBuildCredentialsId: ID!
42
42
  $isDefault: Boolean!
43
43
  ) {
@@ -55,7 +55,7 @@ exports.AndroidAppBuildCredentialsMutation = {
55
55
  })
56
56
  .toPromise());
57
57
  (0, assert_1.default)(data, `GraphQL: 'setDefault' not defined in server response ${JSON.stringify(data)}}`);
58
- return data;
58
+ return data.androidAppBuildCredentials.setDefault;
59
59
  },
60
60
  async setKeystoreAsync(graphqlClient, androidAppBuildCredentialsId, keystoreId) {
61
61
  const data = await (0, client_1.withErrorHandlingAsync)(graphqlClient
@@ -109,6 +109,8 @@ export type Account = {
109
109
  googleServiceAccountKeys: Array<GoogleServiceAccountKey>;
110
110
  id: Scalars['ID'];
111
111
  isCurrent: Scalars['Boolean'];
112
+ /** Whether this account has SSO enabled. Can be queried by all members. */
113
+ isSSOEnabled: Scalars['Boolean'];
112
114
  name: Scalars['String'];
113
115
  /** Offers set on this account */
114
116
  offers?: Maybe<Array<Offer>>;
@@ -822,6 +824,7 @@ export type AndroidSubmissionConfig = {
822
824
  /** @deprecated archiveType is deprecated and will be null */
823
825
  archiveType?: Maybe<SubmissionAndroidArchiveType>;
824
826
  releaseStatus?: Maybe<SubmissionAndroidReleaseStatus>;
827
+ rollout?: Maybe<Scalars['Float']>;
825
828
  track: SubmissionAndroidTrack;
826
829
  };
827
830
  export type AndroidSubmissionConfigInput = {
@@ -831,6 +834,7 @@ export type AndroidSubmissionConfigInput = {
831
834
  googleServiceAccountKeyId?: InputMaybe<Scalars['String']>;
832
835
  googleServiceAccountKeyJson?: InputMaybe<Scalars['String']>;
833
836
  releaseStatus?: InputMaybe<SubmissionAndroidReleaseStatus>;
837
+ rollout?: InputMaybe<Scalars['Float']>;
834
838
  track: SubmissionAndroidTrack;
835
839
  };
836
840
  /** Represents an Exponent App (or Experience in legacy terms) */
@@ -1672,7 +1676,8 @@ export type BackgroundJobReceiptQueryByIdArgs = {
1672
1676
  id: Scalars['ID'];
1673
1677
  };
1674
1678
  export declare enum BackgroundJobResultType {
1675
- GithubBuild = "GITHUB_BUILD"
1679
+ GithubBuild = "GITHUB_BUILD",
1680
+ Void = "VOID"
1676
1681
  }
1677
1682
  export declare enum BackgroundJobState {
1678
1683
  Failure = "FAILURE",
@@ -1731,6 +1736,7 @@ export type Build = ActivityTimelineProjectActivity & BuildOrBuildJob & {
1731
1736
  initiatingUser?: Maybe<User>;
1732
1737
  iosEnterpriseProvisioning?: Maybe<BuildIosEnterpriseProvisioning>;
1733
1738
  isGitWorkingTreeDirty?: Maybe<Scalars['Boolean']>;
1739
+ isWaived: Scalars['Boolean'];
1734
1740
  logFiles: Array<Scalars['String']>;
1735
1741
  maxBuildTimeSeconds: Scalars['Int'];
1736
1742
  /** Retry time starts after completedAt */
@@ -2263,6 +2269,10 @@ export type DeleteRobotResult = {
2263
2269
  __typename?: 'DeleteRobotResult';
2264
2270
  id: Scalars['ID'];
2265
2271
  };
2272
+ export type DeleteSsoUserResult = {
2273
+ __typename?: 'DeleteSSOUserResult';
2274
+ id: Scalars['ID'];
2275
+ };
2266
2276
  export type DeleteUpdateBranchResult = {
2267
2277
  __typename?: 'DeleteUpdateBranchResult';
2268
2278
  id: Scalars['ID'];
@@ -2589,7 +2599,7 @@ export type GitHubRepository = {
2589
2599
  githubRepositoryIdentifier: Scalars['Int'];
2590
2600
  githubRepositoryUrl?: Maybe<Scalars['String']>;
2591
2601
  id: Scalars['ID'];
2592
- metadata?: Maybe<GitHubRepositoryMetadata>;
2602
+ metadata: GitHubRepositoryMetadata;
2593
2603
  nodeIdentifier: Scalars['String'];
2594
2604
  };
2595
2605
  export type GitHubRepositoryMetadata = {
@@ -2601,7 +2611,6 @@ export type GitHubRepositoryMetadata = {
2601
2611
  githubRepoUrl: Scalars['String'];
2602
2612
  lastPushed: Scalars['DateTime'];
2603
2613
  lastUpdated: Scalars['DateTime'];
2604
- openGraphImageUrl?: Maybe<Scalars['String']>;
2605
2614
  private: Scalars['Boolean'];
2606
2615
  };
2607
2616
  export type GitHubRepositoryMutation = {
@@ -3030,6 +3039,8 @@ export type MeMutation = {
3030
3039
  createAccount: Account;
3031
3040
  /** Delete an Account created via createAccount */
3032
3041
  deleteAccount: DeleteAccountResult;
3042
+ /** Delete a SSO user. Actor must be an owner on the SSO user's SSO account. */
3043
+ deleteSSOUser: DeleteSsoUserResult;
3033
3044
  /** Delete a second factor device */
3034
3045
  deleteSecondFactorDevice: SecondFactorBooleanResult;
3035
3046
  /** Delete a Snack that the current user owns */
@@ -3072,6 +3083,9 @@ export type MeMutationCreateAccountArgs = {
3072
3083
  export type MeMutationDeleteAccountArgs = {
3073
3084
  accountId: Scalars['ID'];
3074
3085
  };
3086
+ export type MeMutationDeleteSsoUserArgs = {
3087
+ ssoUserId: Scalars['ID'];
3088
+ };
3075
3089
  export type MeMutationDeleteSecondFactorDeviceArgs = {
3076
3090
  otp: Scalars['String'];
3077
3091
  userSecondFactorDeviceId: Scalars['ID'];
@@ -3121,6 +3135,7 @@ export type MeteredBillingStatus = {
3121
3135
  };
3122
3136
  export declare enum NotificationEvent {
3123
3137
  BuildComplete = "BUILD_COMPLETE",
3138
+ BuildLimitThresholdExceeded = "BUILD_LIMIT_THRESHOLD_EXCEEDED",
3124
3139
  BuildPlanCreditThresholdExceeded = "BUILD_PLAN_CREDIT_THRESHOLD_EXCEEDED",
3125
3140
  SubmissionComplete = "SUBMISSION_COMPLETE"
3126
3141
  }
@@ -3515,6 +3530,8 @@ export type RootQuery = {
3515
3530
  user: UserQuery;
3516
3531
  /** Top-level query object for querying UserActors. */
3517
3532
  userActor: UserActorQuery;
3533
+ /** Top-level query object for querying UserActorPublicData publicly. */
3534
+ userActorPublicData: UserActorPublicDataQuery;
3518
3535
  /** @deprecated Use 'byId' field under 'user'. */
3519
3536
  userByUserId?: Maybe<User>;
3520
3537
  /** @deprecated Use 'byUsername' field under 'user'. */
@@ -4195,7 +4212,7 @@ export type User = Actor & UserActor & {
4195
4212
  /** Discord account linked to a user */
4196
4213
  discordUser?: Maybe<DiscordUser>;
4197
4214
  displayName: Scalars['String'];
4198
- email?: Maybe<Scalars['String']>;
4215
+ email: Scalars['String'];
4199
4216
  emailVerified: Scalars['Boolean'];
4200
4217
  /**
4201
4218
  * Server feature gate values for this actor, optionally filtering by desired gates.
@@ -4336,6 +4353,38 @@ export type UserActorSnacksArgs = {
4336
4353
  limit: Scalars['Int'];
4337
4354
  offset: Scalars['Int'];
4338
4355
  };
4356
+ /** A human user (type User or SSOUser) that can login to the Expo website, use Expo services, and be a member of accounts. */
4357
+ export type UserActorPublicData = {
4358
+ __typename?: 'UserActorPublicData';
4359
+ /** Apps this user has published */
4360
+ apps: Array<App>;
4361
+ firstName?: Maybe<Scalars['String']>;
4362
+ id: Scalars['ID'];
4363
+ lastName?: Maybe<Scalars['String']>;
4364
+ profilePhoto: Scalars['String'];
4365
+ /** Snacks associated with this user's personal account */
4366
+ snacks: Array<Snack>;
4367
+ username: Scalars['String'];
4368
+ };
4369
+ /** A human user (type User or SSOUser) that can login to the Expo website, use Expo services, and be a member of accounts. */
4370
+ export type UserActorPublicDataAppsArgs = {
4371
+ includeUnpublished?: InputMaybe<Scalars['Boolean']>;
4372
+ limit: Scalars['Int'];
4373
+ offset: Scalars['Int'];
4374
+ };
4375
+ /** A human user (type User or SSOUser) that can login to the Expo website, use Expo services, and be a member of accounts. */
4376
+ export type UserActorPublicDataSnacksArgs = {
4377
+ limit: Scalars['Int'];
4378
+ offset: Scalars['Int'];
4379
+ };
4380
+ export type UserActorPublicDataQuery = {
4381
+ __typename?: 'UserActorPublicDataQuery';
4382
+ /** Get UserActorPublicData by username */
4383
+ byUsername: UserActorPublicData;
4384
+ };
4385
+ export type UserActorPublicDataQueryByUsernameArgs = {
4386
+ username: Scalars['String'];
4387
+ };
4339
4388
  export type UserActorQuery = {
4340
4389
  __typename?: 'UserActorQuery';
4341
4390
  /** Query a UserActor by ID */
@@ -4719,6 +4768,37 @@ export type CreateAndroidAppBuildCredentialsMutation = {
4719
4768
  };
4720
4769
  };
4721
4770
  };
4771
+ export type SetDefaultAndroidAppBuildCredentialsMutationVariables = Exact<{
4772
+ androidAppBuildCredentialsId: Scalars['ID'];
4773
+ isDefault: Scalars['Boolean'];
4774
+ }>;
4775
+ export type SetDefaultAndroidAppBuildCredentialsMutation = {
4776
+ __typename?: 'RootMutation';
4777
+ androidAppBuildCredentials: {
4778
+ __typename?: 'AndroidAppBuildCredentialsMutation';
4779
+ setDefault: {
4780
+ __typename?: 'AndroidAppBuildCredentials';
4781
+ id: string;
4782
+ isDefault: boolean;
4783
+ isLegacy: boolean;
4784
+ name: string;
4785
+ androidKeystore?: {
4786
+ __typename?: 'AndroidKeystore';
4787
+ id: string;
4788
+ type: AndroidKeystoreType;
4789
+ keystore: string;
4790
+ keystorePassword: string;
4791
+ keyAlias: string;
4792
+ keyPassword?: string | null;
4793
+ md5CertificateFingerprint?: string | null;
4794
+ sha1CertificateFingerprint?: string | null;
4795
+ sha256CertificateFingerprint?: string | null;
4796
+ createdAt: any;
4797
+ updatedAt: any;
4798
+ } | null;
4799
+ };
4800
+ };
4801
+ };
4722
4802
  export type SetKeystoreMutationVariables = Exact<{
4723
4803
  androidAppBuildCredentialsId: Scalars['ID'];
4724
4804
  keystoreId: Scalars['ID'];
@@ -8025,6 +8105,7 @@ export type CreateAndroidSubmissionMutation = {
8025
8105
  applicationIdentifier?: string | null;
8026
8106
  track: SubmissionAndroidTrack;
8027
8107
  releaseStatus?: SubmissionAndroidReleaseStatus | null;
8108
+ rollout?: number | null;
8028
8109
  } | null;
8029
8110
  iosConfig?: {
8030
8111
  __typename?: 'IosSubmissionConfig';
@@ -8074,6 +8155,7 @@ export type CreateIosSubmissionMutation = {
8074
8155
  applicationIdentifier?: string | null;
8075
8156
  track: SubmissionAndroidTrack;
8076
8157
  releaseStatus?: SubmissionAndroidReleaseStatus | null;
8158
+ rollout?: number | null;
8077
8159
  } | null;
8078
8160
  iosConfig?: {
8079
8161
  __typename?: 'IosSubmissionConfig';
@@ -8507,6 +8589,7 @@ export type BuildsWithSubmissionsByIdQuery = {
8507
8589
  applicationIdentifier?: string | null;
8508
8590
  track: SubmissionAndroidTrack;
8509
8591
  releaseStatus?: SubmissionAndroidReleaseStatus | null;
8592
+ rollout?: number | null;
8510
8593
  } | null;
8511
8594
  iosConfig?: {
8512
8595
  __typename?: 'IosSubmissionConfig';
@@ -8884,6 +8967,7 @@ export type SubmissionsByIdQuery = {
8884
8967
  applicationIdentifier?: string | null;
8885
8968
  track: SubmissionAndroidTrack;
8886
8969
  releaseStatus?: SubmissionAndroidReleaseStatus | null;
8970
+ rollout?: number | null;
8887
8971
  } | null;
8888
8972
  iosConfig?: {
8889
8973
  __typename?: 'IosSubmissionConfig';
@@ -8934,6 +9018,7 @@ export type GetAllSubmissionsForAppQuery = {
8934
9018
  applicationIdentifier?: string | null;
8935
9019
  track: SubmissionAndroidTrack;
8936
9020
  releaseStatus?: SubmissionAndroidReleaseStatus | null;
9021
+ rollout?: number | null;
8937
9022
  } | null;
8938
9023
  iosConfig?: {
8939
9024
  __typename?: 'IosSubmissionConfig';
@@ -9422,6 +9507,7 @@ export type BuildWithSubmissionsFragment = {
9422
9507
  applicationIdentifier?: string | null;
9423
9508
  track: SubmissionAndroidTrack;
9424
9509
  releaseStatus?: SubmissionAndroidReleaseStatus | null;
9510
+ rollout?: number | null;
9425
9511
  } | null;
9426
9512
  iosConfig?: {
9427
9513
  __typename?: 'IosSubmissionConfig';
@@ -9519,6 +9605,7 @@ export type SubmissionFragment = {
9519
9605
  applicationIdentifier?: string | null;
9520
9606
  track: SubmissionAndroidTrack;
9521
9607
  releaseStatus?: SubmissionAndroidReleaseStatus | null;
9608
+ rollout?: number | null;
9522
9609
  } | null;
9523
9610
  iosConfig?: {
9524
9611
  __typename?: 'IosSubmissionConfig';
@@ -103,6 +103,7 @@ var AuthProtocolType;
103
103
  var BackgroundJobResultType;
104
104
  (function (BackgroundJobResultType) {
105
105
  BackgroundJobResultType["GithubBuild"] = "GITHUB_BUILD";
106
+ BackgroundJobResultType["Void"] = "VOID";
106
107
  })(BackgroundJobResultType = exports.BackgroundJobResultType || (exports.BackgroundJobResultType = {}));
107
108
  var BackgroundJobState;
108
109
  (function (BackgroundJobState) {
@@ -302,6 +303,7 @@ var MailchimpTag;
302
303
  var NotificationEvent;
303
304
  (function (NotificationEvent) {
304
305
  NotificationEvent["BuildComplete"] = "BUILD_COMPLETE";
306
+ NotificationEvent["BuildLimitThresholdExceeded"] = "BUILD_LIMIT_THRESHOLD_EXCEEDED";
305
307
  NotificationEvent["BuildPlanCreditThresholdExceeded"] = "BUILD_PLAN_CREDIT_THRESHOLD_EXCEEDED";
306
308
  NotificationEvent["SubmissionComplete"] = "SUBMISSION_COMPLETE";
307
309
  })(NotificationEvent = exports.NotificationEvent || (exports.NotificationEvent = {}));
@@ -21,6 +21,7 @@ exports.SubmissionFragmentNode = (0, graphql_tag_1.default) `
21
21
  applicationIdentifier
22
22
  track
23
23
  releaseStatus
24
+ rollout
24
25
  }
25
26
  iosConfig {
26
27
  ascAppIdentifier
@@ -4,6 +4,7 @@ exports.getNativeTargetEntitlementsAsync = exports.getManagedApplicationTargetEn
4
4
  const config_plugins_1 = require("@expo/config-plugins");
5
5
  const prebuild_config_1 = require("@expo/prebuild-config");
6
6
  const plist_1 = require("../../utils/plist");
7
+ const workflow_1 = require("../workflow");
7
8
  async function getManagedApplicationTargetEntitlementsAsync(projectDir, env) {
8
9
  var _a;
9
10
  const originalProcessEnv = process.env;
@@ -17,6 +18,7 @@ async function getManagedApplicationTargetEntitlementsAsync(projectDir, env) {
17
18
  projectRoot: projectDir,
18
19
  platforms: ['ios'],
19
20
  introspect: true,
21
+ ignoreExistingNativeFiles: await (0, workflow_1.hasIgnoredIosProjectAsync)(projectDir),
20
22
  });
21
23
  return ((_a = expWithMods.ios) === null || _a === void 0 ? void 0 : _a.entitlements) || {};
22
24
  }
@@ -1,3 +1,4 @@
1
1
  import { Platform, Workflow } from '@expo/eas-build-job';
2
2
  export declare function resolveWorkflowAsync(projectDir: string, platform: Platform): Promise<Workflow>;
3
3
  export declare function resolveWorkflowPerPlatformAsync(projectDir: string): Promise<Record<Platform, Workflow>>;
4
+ export declare function hasIgnoredIosProjectAsync(projectDir: string): Promise<boolean>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.resolveWorkflowPerPlatformAsync = exports.resolveWorkflowAsync = void 0;
3
+ exports.hasIgnoredIosProjectAsync = 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");
@@ -40,3 +40,15 @@ async function resolveWorkflowPerPlatformAsync(projectDir) {
40
40
  return { android, ios };
41
41
  }
42
42
  exports.resolveWorkflowPerPlatformAsync = resolveWorkflowPerPlatformAsync;
43
+ async function hasIgnoredIosProjectAsync(projectDir) {
44
+ const vcsClient = (0, vcs_1.getVcsClient)();
45
+ const vcsRootPath = path_1.default.normalize(await vcsClient.getRootPathAsync());
46
+ try {
47
+ const pbxProjectPath = config_plugins_1.IOSConfig.Paths.getPBXProjectPath(projectDir);
48
+ return await vcsClient.isFileIgnoredAsync(path_1.default.relative(vcsRootPath, pbxProjectPath));
49
+ }
50
+ finally {
51
+ return false;
52
+ }
53
+ }
54
+ exports.hasIgnoredIosProjectAsync = hasIgnoredIosProjectAsync;
@@ -0,0 +1,53 @@
1
+ import { BranchMapping } from '../channel/branch-mapping';
2
+ /**
3
+ * Detect if a branch mapping is a rollout.
4
+ *
5
+ * Types of rollout:
6
+ * 1. Legacy unconstrained rollout:
7
+ * Maps to a rollout branch via a rollout token
8
+ * Falls back to a default branch
9
+ *
10
+ * Example:
11
+ * {
12
+ version: 0,
13
+ data: [
14
+ {
15
+ branchId: uuidv4(),
16
+ branchMappingLogic: {
17
+ operand: 10 / 100,
18
+ clientKey: 'rolloutToken',
19
+ branchMappingOperator: hashLtOperator(),
20
+ },
21
+ },
22
+ { branchId: uuidv4(), branchMappingLogic: alwaysTrue() },
23
+ ],
24
+ }
25
+ *
26
+ * 2. RTV constrained rollout:
27
+ * Maps to a rollout branch via a rollout token, constrained by runtime version
28
+ * Falls back to a default branch
29
+ *
30
+ * Example:
31
+ * {
32
+ version: 0,
33
+ data: [
34
+ {
35
+ branchId: uuidv4(),
36
+ branchMappingLogic: andStatement([
37
+ {
38
+ operand: '1.0.0',
39
+ clientKey: 'runtimeVersion',
40
+ branchMappingOperator: equalsOperator(),
41
+ },
42
+ {
43
+ operand: 10 / 100,
44
+ clientKey: 'rolloutToken',
45
+ branchMappingOperator: hashLtOperator(),
46
+ },
47
+ ]),
48
+ },
49
+ { branchId: uuidv4(), branchMappingLogic: alwaysTrue() },
50
+ ],
51
+ }
52
+ */
53
+ export declare function isRollout(branchMapping: BranchMapping): boolean;
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isRollout = void 0;
4
+ const branch_mapping_1 = require("../channel/branch-mapping");
5
+ /**
6
+ * Detect if a branch mapping is a rollout.
7
+ *
8
+ * Types of rollout:
9
+ * 1. Legacy unconstrained rollout:
10
+ * Maps to a rollout branch via a rollout token
11
+ * Falls back to a default branch
12
+ *
13
+ * Example:
14
+ * {
15
+ version: 0,
16
+ data: [
17
+ {
18
+ branchId: uuidv4(),
19
+ branchMappingLogic: {
20
+ operand: 10 / 100,
21
+ clientKey: 'rolloutToken',
22
+ branchMappingOperator: hashLtOperator(),
23
+ },
24
+ },
25
+ { branchId: uuidv4(), branchMappingLogic: alwaysTrue() },
26
+ ],
27
+ }
28
+ *
29
+ * 2. RTV constrained rollout:
30
+ * Maps to a rollout branch via a rollout token, constrained by runtime version
31
+ * Falls back to a default branch
32
+ *
33
+ * Example:
34
+ * {
35
+ version: 0,
36
+ data: [
37
+ {
38
+ branchId: uuidv4(),
39
+ branchMappingLogic: andStatement([
40
+ {
41
+ operand: '1.0.0',
42
+ clientKey: 'runtimeVersion',
43
+ branchMappingOperator: equalsOperator(),
44
+ },
45
+ {
46
+ operand: 10 / 100,
47
+ clientKey: 'rolloutToken',
48
+ branchMappingOperator: hashLtOperator(),
49
+ },
50
+ ]),
51
+ },
52
+ { branchId: uuidv4(), branchMappingLogic: alwaysTrue() },
53
+ ],
54
+ }
55
+ */
56
+ function isRollout(branchMapping) {
57
+ return isUnconstrainedRollout(branchMapping) || isRtvConstrainedRollout(branchMapping);
58
+ }
59
+ exports.isRollout = isRollout;
60
+ function isRtvConstrainedRollout(branchMapping) {
61
+ if (branchMapping.data.length !== 2) {
62
+ return false;
63
+ }
64
+ const hasRtvRolloutNode = isRtvConstrainedRolloutNode(branchMapping.data[0].branchMappingLogic);
65
+ const defaultsToAlwaysTrueNode = (0, branch_mapping_1.isAlwaysTrue)(branchMapping.data[1].branchMappingLogic);
66
+ return hasRtvRolloutNode && defaultsToAlwaysTrueNode;
67
+ }
68
+ function isRtvConstrainedRolloutNode(node) {
69
+ if (!(0, branch_mapping_1.isStatement)(node) || !(0, branch_mapping_1.isAndStatement)(node)) {
70
+ return false;
71
+ }
72
+ const statementNodes = (0, branch_mapping_1.getNodesFromStatement)(node);
73
+ if (statementNodes.length !== 2) {
74
+ return false;
75
+ }
76
+ const hasRuntimeVersionNode = statementNodes.some(isRuntimeVersionNode);
77
+ const hasRolloutNode = statementNodes.some(isRolloutNode);
78
+ return hasRuntimeVersionNode && hasRolloutNode;
79
+ }
80
+ function isUnconstrainedRollout(branchMapping) {
81
+ if (branchMapping.data.length !== 2) {
82
+ return false;
83
+ }
84
+ const hasRolloutNode = isRolloutNode(branchMapping.data[0].branchMappingLogic);
85
+ const defaultsToAlwaysTrueNode = (0, branch_mapping_1.isAlwaysTrue)(branchMapping.data[1].branchMappingLogic);
86
+ return hasRolloutNode && defaultsToAlwaysTrueNode;
87
+ }
88
+ function isRuntimeVersionNode(node) {
89
+ if (typeof node === 'string') {
90
+ return false;
91
+ }
92
+ if (Array.isArray(node)) {
93
+ return false;
94
+ }
95
+ return node.clientKey === 'runtimeVersion' && node.branchMappingOperator === '==';
96
+ }
97
+ function isRolloutNode(node) {
98
+ if (typeof node === 'string') {
99
+ return false;
100
+ }
101
+ if (Array.isArray(node)) {
102
+ return false;
103
+ }
104
+ return node.clientKey === 'rolloutToken' && node.branchMappingOperator === 'hash_lt';
105
+ }
@@ -9,6 +9,7 @@ export default class AndroidSubmitCommand {
9
9
  private maybeGetAndroidPackageFromCurrentProjectAsync;
10
10
  private resolveTrack;
11
11
  private resolveReleaseStatus;
12
+ private resolveRollout;
12
13
  private resolveArchiveSource;
13
14
  private resolveServiceAccountSourceAsync;
14
15
  }
@@ -24,8 +24,9 @@ class AndroidSubmitCommand {
24
24
  const track = this.resolveTrack();
25
25
  const releaseStatus = this.resolveReleaseStatus();
26
26
  const archiveSource = this.resolveArchiveSource();
27
+ const rollout = this.resolveRollout();
27
28
  const serviceAccountSource = await this.resolveServiceAccountSourceAsync();
28
- const errored = [track, releaseStatus, archiveSource, serviceAccountSource].filter(r => !r.ok);
29
+ const errored = [track, releaseStatus, archiveSource, serviceAccountSource, rollout].filter(r => !r.ok);
29
30
  if (errored.length > 0) {
30
31
  const message = errored.map(err => { var _a; return (_a = err.reason) === null || _a === void 0 ? void 0 : _a.message; }).join('\n');
31
32
  log_1.default.error(message);
@@ -35,6 +36,7 @@ class AndroidSubmitCommand {
35
36
  projectId: this.ctx.projectId,
36
37
  track: track.enforceValue(),
37
38
  releaseStatus: releaseStatus.enforceValue(),
39
+ rollout: rollout.enforceValue(),
38
40
  archiveSource: archiveSource.enforceValue(),
39
41
  serviceAccountSource: serviceAccountSource.enforceValue(),
40
42
  changesNotSentForReview: this.ctx.profile.changesNotSentForReview,
@@ -78,6 +80,10 @@ class AndroidSubmitCommand {
78
80
  return (0, results_1.result)(new Error(`Unsupported release status: ${releaseStatus} (valid options: ${Object.keys(eas_json_1.AndroidReleaseStatus).join(', ')})`));
79
81
  }
80
82
  }
83
+ resolveRollout() {
84
+ const { rollout } = this.ctx.profile;
85
+ return (0, results_1.result)(rollout);
86
+ }
81
87
  resolveArchiveSource() {
82
88
  try {
83
89
  return (0, results_1.result)((0, commons_1.resolveArchiveSource)(this.ctx));
@@ -4,7 +4,7 @@ import { ArchiveSource, ResolvedArchiveSource } from '../ArchiveSource';
4
4
  import BaseSubmitter, { SubmissionInput } from '../BaseSubmitter';
5
5
  import { SubmissionContext } from '../context';
6
6
  import { ServiceAccountKeyResult, ServiceAccountSource } from './ServiceAccountSource';
7
- export interface AndroidSubmissionOptions extends Pick<AndroidSubmissionConfigInput, 'track' | 'releaseStatus' | 'changesNotSentForReview'> {
7
+ export interface AndroidSubmissionOptions extends Pick<AndroidSubmissionConfigInput, 'track' | 'releaseStatus' | 'changesNotSentForReview' | 'rollout'> {
8
8
  projectId: string;
9
9
  archiveSource: ArchiveSource;
10
10
  serviceAccountSource: ServiceAccountSource;