eas-cli 14.4.1 → 14.6.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 (58) hide show
  1. package/README.md +147 -91
  2. package/build/build/android/graphql.js +2 -0
  3. package/build/build/android/prepareJob.js +1 -0
  4. package/build/build/android/version.d.ts +1 -0
  5. package/build/build/android/version.js +5 -1
  6. package/build/build/build.js +4 -3
  7. package/build/build/configure.d.ts +11 -0
  8. package/build/build/configure.js +46 -1
  9. package/build/build/evaluateConfigWithEnvVarsAsync.js +2 -4
  10. package/build/build/ios/build.js +2 -0
  11. package/build/build/ios/graphql.js +2 -0
  12. package/build/build/ios/prepareJob.js +1 -0
  13. package/build/build/ios/version.js +4 -1
  14. package/build/build/local.js +1 -1
  15. package/build/build/metadata.js +0 -1
  16. package/build/build/runBuildAndSubmit.d.ts +12 -1
  17. package/build/build/runBuildAndSubmit.js +16 -13
  18. package/build/build/utils/environment.d.ts +4 -0
  19. package/build/build/utils/environment.js +20 -0
  20. package/build/commands/build/dev.d.ts +23 -0
  21. package/build/commands/build/dev.js +225 -0
  22. package/build/commands/build/index.js +9 -1
  23. package/build/commands/build/inspect.js +26 -18
  24. package/build/commands/build/internal.js +22 -14
  25. package/build/commands/build/list.d.ts +1 -0
  26. package/build/commands/build/list.js +4 -0
  27. package/build/commands/{worker → deploy}/alias.js +4 -4
  28. package/build/commands/{worker/deploy.js → deploy/index.js} +5 -5
  29. package/build/commands/fingerprint/compare.d.ts +14 -1
  30. package/build/commands/fingerprint/compare.js +192 -53
  31. package/build/commands/project/onboarding.js +23 -14
  32. package/build/commands/update/index.js +3 -6
  33. package/build/commands/update/roll-back-to-embedded.js +2 -2
  34. package/build/credentials/ios/appstore/ensureAppExists.d.ts +22 -1
  35. package/build/credentials/ios/appstore/ensureAppExists.js +73 -2
  36. package/build/credentials/ios/appstore/ensureTestFlightGroup.d.ts +7 -0
  37. package/build/credentials/ios/appstore/ensureTestFlightGroup.js +158 -0
  38. package/build/credentials/ios/appstore/provisioningProfile.js +1 -0
  39. package/build/credentials/ios/appstore/resolveCredentials.js +6 -1
  40. package/build/graphql/generated.d.ts +313 -3
  41. package/build/graphql/generated.js +11 -2
  42. package/build/graphql/queries/FingerprintQuery.d.ts +16 -0
  43. package/build/graphql/queries/FingerprintQuery.js +61 -0
  44. package/build/graphql/types/Fingerprint.js +18 -0
  45. package/build/project/ios/exemptEncryption.d.ts +7 -0
  46. package/build/project/ios/exemptEncryption.js +80 -0
  47. package/build/project/publish.d.ts +4 -4
  48. package/build/project/publish.js +9 -8
  49. package/build/project/resolveRuntimeVersionAsync.d.ts +4 -4
  50. package/build/project/resolveRuntimeVersionAsync.js +4 -4
  51. package/build/submit/ios/AppProduce.js +12 -23
  52. package/build/utils/fingerprintCli.d.ts +2 -1
  53. package/build/utils/fingerprintCli.js +11 -3
  54. package/build/worker/upload.js +19 -3
  55. package/oclif.manifest.json +217 -155
  56. package/package.json +6 -6
  57. /package/build/commands/{worker → deploy}/alias.d.ts +0 -0
  58. /package/build/commands/{worker/deploy.d.ts → deploy/index.d.ts} +0 -0
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ensureTestFlightGroupExistsAsync = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const apple_utils_1 = require("@expo/apple-utils");
6
+ const ensureAppExists_1 = require("./ensureAppExists");
7
+ const log_1 = tslib_1.__importDefault(require("../../../log"));
8
+ const ora_1 = require("../../../ora");
9
+ const prompts_1 = require("../../../prompts");
10
+ // The name of the internal TestFlight group, this should probably never change.
11
+ const AUTO_GROUP_NAME = 'Team (Expo)';
12
+ /**
13
+ * Ensure a TestFlight internal group with access to all builds exists for the app and has all admin users invited to it.
14
+ * This allows users to instantly access their builds from TestFlight after it finishes processing.
15
+ */
16
+ async function ensureTestFlightGroupExistsAsync(app) {
17
+ const group = await ensureInternalGroupAsync(app);
18
+ const users = await apple_utils_1.User.getAsync(app.context);
19
+ const admins = users.filter(user => user.attributes.roles?.includes(apple_utils_1.UserRole.ADMIN));
20
+ await addAllUsersToInternalGroupAsync(group, admins);
21
+ }
22
+ exports.ensureTestFlightGroupExistsAsync = ensureTestFlightGroupExistsAsync;
23
+ async function ensureInternalGroupAsync(app) {
24
+ const groups = await app.getBetaGroupsAsync({
25
+ query: {
26
+ includes: ['betaTesters'],
27
+ },
28
+ });
29
+ let betaGroup = groups.find(group => group.attributes.name === AUTO_GROUP_NAME);
30
+ if (!betaGroup) {
31
+ const spinner = (0, ora_1.ora)().start('Creating TestFlight group...');
32
+ try {
33
+ // Apple throw an error if you create the group too quickly after creating the app. We'll retry a few times.
34
+ await pollRetryAsync(async () => {
35
+ betaGroup = await app.createBetaGroupAsync({
36
+ name: AUTO_GROUP_NAME,
37
+ publicLinkEnabled: false,
38
+ publicLinkLimitEnabled: false,
39
+ isInternalGroup: true,
40
+ // Automatically add latest builds to the group without needing to run the command.
41
+ hasAccessToAllBuilds: true,
42
+ });
43
+ }, {
44
+ shouldRetry(error) {
45
+ if ((0, ensureAppExists_1.isAppleError)(error)) {
46
+ spinner.text = `TestFlight not ready, retrying in 25 seconds...`;
47
+ return error.data.errors.some(error => error.code === 'ENTITY_ERROR.RELATIONSHIP.INVALID');
48
+ }
49
+ return false;
50
+ },
51
+ });
52
+ spinner.succeed(`TestFlight group created: ${AUTO_GROUP_NAME}`);
53
+ }
54
+ catch (error) {
55
+ spinner.fail('Failed to create TestFlight group...');
56
+ throw error;
57
+ }
58
+ }
59
+ if (!betaGroup) {
60
+ throw new Error('Failed to create internal TestFlight group');
61
+ }
62
+ // `hasAccessToAllBuilds` is a newer feature that allows the group to automatically have access to all builds. This cannot be patched so we need to recreate the group.
63
+ if (!betaGroup.attributes.hasAccessToAllBuilds) {
64
+ if (await (0, prompts_1.confirmAsync)({
65
+ message: 'Regenerate internal TestFlight group to allow automatic access to all builds?',
66
+ })) {
67
+ await apple_utils_1.BetaGroup.deleteAsync(app.context, { id: betaGroup.id });
68
+ return await ensureInternalGroupAsync(app);
69
+ }
70
+ }
71
+ return betaGroup;
72
+ }
73
+ async function addAllUsersToInternalGroupAsync(group, users) {
74
+ let emails = users
75
+ .filter(user => user.attributes.email)
76
+ .map(user => ({
77
+ email: user.attributes.email,
78
+ firstName: user.attributes.firstName ?? '',
79
+ lastName: user.attributes.lastName ?? '',
80
+ }));
81
+ const { betaTesters } = group.attributes;
82
+ const existingEmails = betaTesters?.map(tester => tester.attributes.email).filter(Boolean) ?? [];
83
+ // Filter out existing beta testers.
84
+ if (betaTesters) {
85
+ emails = emails.filter(user => !existingEmails.find(existingEmail => existingEmail === user.email));
86
+ }
87
+ // No new users to add to the internal group.
88
+ if (!emails.length) {
89
+ // No need to log which users are here on subsequent runs as devs already know the drill at this point.
90
+ log_1.default.debug(`All current admins are already added to the group: ${group.attributes.name}`);
91
+ return;
92
+ }
93
+ log_1.default.debug(`Adding ${emails.length} users to internal group: ${group.attributes.name}`);
94
+ log_1.default.debug(`Users: ${emails.map(user => user.email).join(', ')}`);
95
+ const data = await group.createBulkBetaTesterAssignmentsAsync(emails);
96
+ const success = data.attributes.betaTesters.every(tester => {
97
+ if (tester.assignmentResult === 'FAILED') {
98
+ if (tester.errors && Array.isArray(tester.errors) && tester.errors.length) {
99
+ if (tester.errors.length === 1 &&
100
+ tester.errors[0].key === 'Halliday.tester.already.exists') {
101
+ return true;
102
+ }
103
+ for (const error of tester.errors) {
104
+ log_1.default.error(`Error adding user ${tester.email} to TestFlight group "${group.attributes.name}": ${error.key}`);
105
+ }
106
+ }
107
+ return false;
108
+ }
109
+ if (tester.assignmentResult === 'NOT_QUALIFIED_FOR_INTERNAL_GROUP') {
110
+ return false;
111
+ }
112
+ return true;
113
+ });
114
+ if (!success) {
115
+ const groupUrl = await getTestFlightGroupUrlAsync(group);
116
+ log_1.default.error(`Unable to add all admins to TestFlight group "${group.attributes.name}". You can add them manually in App Store Connect. ${groupUrl ?? ''}`);
117
+ }
118
+ else {
119
+ log_1.default.log(`TestFlight access enabled for: ` +
120
+ data.attributes.betaTesters
121
+ .map(tester => tester.email)
122
+ .filter(Boolean)
123
+ .join(', '));
124
+ // TODO: When we have more TestFlight functionality, we can link to it from here.
125
+ }
126
+ }
127
+ async function getTestFlightGroupUrlAsync(group) {
128
+ if (group.context.providerId) {
129
+ try {
130
+ const session = await apple_utils_1.Session.getSessionForProviderIdAsync(group.context.providerId);
131
+ return `https://appstoreconnect.apple.com/teams/${session.provider.publicProviderId}/apps/6741088859/testflight/groups/${group.id}`;
132
+ }
133
+ catch (error) {
134
+ // Avoid crashing if we can't get the session.
135
+ log_1.default.debug('Failed to get session for provider ID', error);
136
+ }
137
+ }
138
+ return null;
139
+ }
140
+ async function pollRetryAsync(fn, { shouldRetry, retries = 10,
141
+ // 25 seconds was the minium interval I calculated when measuring against 5 second intervals.
142
+ interval = 25000, } = {}) {
143
+ let lastError = null;
144
+ for (let i = 0; i < retries; i++) {
145
+ try {
146
+ return await fn();
147
+ }
148
+ catch (error) {
149
+ if (shouldRetry && !shouldRetry(error)) {
150
+ throw error;
151
+ }
152
+ lastError = error;
153
+ await new Promise(resolve => setTimeout(resolve, interval));
154
+ }
155
+ }
156
+ // eslint-disable-next-line @typescript-eslint/no-throw-literal
157
+ throw lastError;
158
+ }
@@ -20,6 +20,7 @@ function resolveProfileType(applePlatform, profileClass, isEnterprise) {
20
20
  return resolveProfileTypeIos(profileClass, isEnterprise);
21
21
  case constants_1.ApplePlatform.TV_OS:
22
22
  return resolveProfileTypeAppleTv(profileClass, isEnterprise);
23
+ case constants_1.ApplePlatform.VISION_OS:
23
24
  case constants_1.ApplePlatform.MAC_OS:
24
25
  throw new Error(`${applePlatform} profiles are not supported`);
25
26
  }
@@ -162,13 +162,18 @@ async function promptUsernameAsync() {
162
162
  // Get the email address that was last used and set it as
163
163
  // the default value for quicker authentication.
164
164
  const lastAppleId = await getCachedUsernameAsync();
165
- const { username } = await (0, prompts_1.promptAsync)({
165
+ let { username } = await (0, prompts_1.promptAsync)({
166
166
  type: 'text',
167
167
  name: 'username',
168
168
  message: `Apple ID:`,
169
169
  validate: (val) => val !== '',
170
170
  initial: lastAppleId ?? undefined,
171
171
  });
172
+ // https://github.com/expo/eas-cli/issues/2254
173
+ // user got an invalid unprintable character in their username, which was saved to cache and used to prefill the prompt
174
+ // which made them accept the prefilled value not knowing it contains the character and fail to log in
175
+ // this replace makes sure no such characters are used or cached
176
+ username = username.replace(/[\x00-\x1F]/gi, '');
172
177
  if (username && username !== lastAppleId) {
173
178
  await cacheUsernameAsync(username);
174
179
  }