eas-cli 3.8.0 → 3.9.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 (47) hide show
  1. package/README.md +79 -54
  2. package/build/build/build.d.ts +1 -0
  3. package/build/build/build.js +21 -20
  4. package/build/build/errors.d.ts +15 -0
  5. package/build/build/errors.js +25 -0
  6. package/build/build/runBuildAndSubmit.js +1 -1
  7. package/build/commandUtils/EasCommand.d.ts +11 -10
  8. package/build/commandUtils/EasCommand.js +20 -0
  9. package/build/commandUtils/context/DynamicProjectConfigContextField.js +1 -1
  10. package/build/commandUtils/context/contextUtils/findProjectDirAndVerifyProjectSetupAsync.js +1 -1
  11. package/build/commandUtils/errors.d.ts +3 -0
  12. package/build/commandUtils/errors.js +11 -0
  13. package/build/commands/build/index.js +1 -1
  14. package/build/commands/build/internal.js +3 -0
  15. package/build/commands/build/resign.js +1 -1
  16. package/build/commands/build/version/set.js +1 -1
  17. package/build/commands/build/version/sync.js +1 -1
  18. package/build/commands/channel/rollout.d.ts +0 -2
  19. package/build/commands/channel/rollout.js +44 -18
  20. package/build/commands/config.js +1 -1
  21. package/build/commands/metadata/lint.js +1 -1
  22. package/build/commands/metadata/pull.js +1 -1
  23. package/build/commands/metadata/push.js +1 -1
  24. package/build/commands/submit.js +1 -1
  25. package/build/commands/update/index.d.ts +0 -2
  26. package/build/commands/update/index.js +32 -137
  27. package/build/commands/update/republish.js +1 -1
  28. package/build/commands/update/roll-back-to-embedded.d.ts +22 -0
  29. package/build/commands/update/roll-back-to-embedded.js +253 -0
  30. package/build/credentials/ios/IosCredentialsProvider.js +1 -1
  31. package/build/credentials/manager/SelectBuildProfileFromEasJson.js +1 -1
  32. package/build/graphql/generated.d.ts +139 -22
  33. package/build/graphql/generated.js +0 -2
  34. package/build/graphql/types/Update.js +1 -0
  35. package/build/project/customBuildConfig.js +19 -4
  36. package/build/project/publish.d.ts +31 -0
  37. package/build/project/publish.js +147 -2
  38. package/build/update/configure.js +1 -1
  39. package/build/update/utils.d.ts +2 -0
  40. package/build/update/utils.js +30 -13
  41. package/build/utils/code-signing.d.ts +4 -3
  42. package/build/utils/code-signing.js +23 -5
  43. package/build/utils/expoCli.js +3 -2
  44. package/build/utils/expodash/areSetsEqual.d.ts +1 -0
  45. package/build/utils/expodash/areSetsEqual.js +6 -0
  46. package/oclif.manifest.json +1 -1
  47. package/package.json +4 -3
@@ -1,16 +1,11 @@
1
1
  "use strict";
2
2
  var _a;
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.defaultPublishPlatforms = void 0;
5
4
  const tslib_1 = require("tslib");
6
- const config_plugins_1 = require("@expo/config-plugins");
7
- const eas_build_job_1 = require("@expo/eas-build-job");
8
5
  const core_1 = require("@oclif/core");
9
- const assert_1 = tslib_1.__importDefault(require("assert"));
10
6
  const chalk_1 = tslib_1.__importDefault(require("chalk"));
11
7
  const nullthrows_1 = tslib_1.__importDefault(require("nullthrows"));
12
8
  const queries_1 = require("../../branch/queries");
13
- const utils_1 = require("../../branch/utils");
14
9
  const url_1 = require("../../build/utils/url");
15
10
  const queries_2 = require("../../channel/queries");
16
11
  const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasCommand"));
@@ -21,42 +16,21 @@ const generated_1 = require("../../graphql/generated");
21
16
  const PublishMutation_1 = require("../../graphql/mutations/PublishMutation");
22
17
  const log_1 = tslib_1.__importStar(require("../../log"));
23
18
  const ora_1 = require("../../ora");
24
- const platform_1 = require("../../platform");
25
19
  const projectUtils_1 = require("../../project/projectUtils");
26
20
  const publish_1 = require("../../project/publish");
27
- const workflow_1 = require("../../project/workflow");
28
- const prompts_1 = require("../../prompts");
29
21
  const configure_1 = require("../../update/configure");
30
- const getBranchNameFromChannelNameAsync_1 = require("../../update/getBranchNameFromChannelNameAsync");
31
- const utils_2 = require("../../update/utils");
22
+ const utils_1 = require("../../update/utils");
32
23
  const code_signing_1 = require("../../utils/code-signing");
33
24
  const uniqBy_1 = tslib_1.__importDefault(require("../../utils/expodash/uniqBy"));
34
25
  const formatFields_1 = tslib_1.__importDefault(require("../../utils/formatFields"));
35
26
  const json_1 = require("../../utils/json");
36
27
  const statuspageService_1 = require("../../utils/statuspageService");
37
28
  const vcs_1 = require("../../vcs");
38
- exports.defaultPublishPlatforms = ['android', 'ios'];
39
- function getRequestedPlatform(platform) {
40
- switch (platform) {
41
- case 'android':
42
- return platform_1.RequestedPlatform.Android;
43
- case 'ios':
44
- return platform_1.RequestedPlatform.Ios;
45
- case 'web':
46
- return null;
47
- case 'all':
48
- return platform_1.RequestedPlatform.All;
49
- default:
50
- throw new Error(`Unsupported platform: ${platform}`);
51
- }
52
- }
53
29
  class UpdatePublish extends EasCommand_1.default {
54
30
  async runAsync() {
55
- var _b, _c;
56
31
  const { flags: rawFlags } = await this.parse(UpdatePublish);
57
32
  const paginatedQueryOptions = (0, pagination_1.getPaginatedQueryOptions)(rawFlags);
58
- let { auto: autoFlag, platform: platformFlag, channelName, updateMessage, inputDir, skipBundler, privateKeyPath, json: jsonFlag, nonInteractive, } = this.sanitizeFlags(rawFlags);
59
- let branchName = this.sanitizeFlags(rawFlags).branchName;
33
+ const { auto: autoFlag, platform: platformFlag, channelName: channelNameArg, updateMessage: updateMessageArg, inputDir, skipBundler, privateKeyPath, json: jsonFlag, nonInteractive, branchName: branchNameArg, } = this.sanitizeFlags(rawFlags);
60
34
  const { getDynamicProjectConfigAsync, loggedIn: { graphqlClient }, } = await this.getContextAsync(UpdatePublish, {
61
35
  nonInteractive,
62
36
  });
@@ -66,76 +40,33 @@ class UpdatePublish extends EasCommand_1.default {
66
40
  const { exp: expPossiblyWithoutEasUpdateConfigured, projectId, projectDir, } = await getDynamicProjectConfigAsync({
67
41
  isPublicConfig: true,
68
42
  });
69
- const { exp: expPrivate } = await getDynamicProjectConfigAsync({
70
- isPublicConfig: false,
71
- });
72
43
  await (0, statuspageService_1.maybeWarnAboutEasOutagesAsync)(graphqlClient, [generated_1.StatuspageServiceName.EasUpdate]);
73
44
  await (0, configure_1.ensureEASUpdateIsConfiguredAsync)(graphqlClient, {
74
45
  exp: expPossiblyWithoutEasUpdateConfigured,
75
- platform: getRequestedPlatform(platformFlag),
46
+ platform: (0, publish_1.getRequestedPlatform)(platformFlag),
76
47
  projectDir,
77
48
  projectId,
78
49
  });
79
- const { exp } = await getDynamicProjectConfigAsync({});
50
+ const { exp } = await getDynamicProjectConfigAsync({ isPublicConfig: true });
51
+ const { exp: expPrivate } = await getDynamicProjectConfigAsync({
52
+ isPublicConfig: false,
53
+ });
80
54
  const codeSigningInfo = await (0, code_signing_1.getCodeSigningInfoAsync)(expPrivate, privateKeyPath);
81
- let realizedPlatforms = [];
82
- if (channelName && branchName) {
83
- throw new Error('Cannot specify both --channel and --branch. Specify either --channel, --branch, or --auto');
84
- }
85
- if (channelName) {
86
- branchName = await (0, getBranchNameFromChannelNameAsync_1.getBranchNameFromChannelNameAsync)(graphqlClient, projectId, channelName);
87
- }
88
- if (!branchName) {
89
- if (autoFlag) {
90
- branchName = await (0, utils_1.getDefaultBranchNameAsync)();
91
- }
92
- else if (nonInteractive) {
93
- throw new Error('Must supply --channel, --branch or --auto when in non-interactive mode');
94
- }
95
- else {
96
- try {
97
- const branch = await (0, queries_1.selectBranchOnAppAsync)(graphqlClient, {
98
- projectId,
99
- promptTitle: `Which branch would you like to publish on?`,
100
- displayTextForListItem: updateBranch => ({
101
- title: `${updateBranch.name} ${chalk_1.default.grey(`- current update: ${(0, utils_2.formatUpdateMessage)(updateBranch.updates[0])}`)}`,
102
- }),
103
- paginatedQueryOptions,
104
- });
105
- branchName = branch.name;
106
- }
107
- catch {
108
- // unable to select a branch (network error or no branches for project)
109
- ({ name: branchName } = await (0, prompts_1.promptAsync)({
110
- type: 'text',
111
- name: 'name',
112
- message: 'No branches found. Provide a branch name:',
113
- initial: await (0, utils_1.getDefaultBranchNameAsync)(),
114
- validate: value => (value ? true : 'Branch name may not be empty.'),
115
- }));
116
- }
117
- (0, assert_1.default)(branchName, 'Branch name must be specified.');
118
- }
119
- }
120
- if (!updateMessage && autoFlag) {
121
- updateMessage = (_b = (await (0, vcs_1.getVcsClient)().getLastCommitMessageAsync())) === null || _b === void 0 ? void 0 : _b.trim();
122
- }
123
- if (!updateMessage) {
124
- if (nonInteractive) {
125
- throw new Error('Must supply --message or use --auto when in non-interactive mode');
126
- }
127
- const validationMessage = 'publish message may not be empty.';
128
- if (jsonFlag) {
129
- throw new Error(validationMessage);
130
- }
131
- ({ updateMessage } = await (0, prompts_1.promptAsync)({
132
- type: 'text',
133
- name: 'updateMessage',
134
- message: `Provide an update message.`,
135
- initial: (_c = (await (0, vcs_1.getVcsClient)().getLastCommitMessageAsync())) === null || _c === void 0 ? void 0 : _c.trim(),
136
- validate: (value) => (value ? true : validationMessage),
137
- }));
138
- }
55
+ const branchName = await (0, publish_1.getBranchNameForCommandAsync)({
56
+ graphqlClient,
57
+ projectId,
58
+ channelNameArg,
59
+ branchNameArg,
60
+ autoFlag,
61
+ nonInteractive,
62
+ paginatedQueryOptions,
63
+ });
64
+ const updateMessage = await (0, publish_1.getUpdateMessageForCommandAsync)({
65
+ updateMessageArg,
66
+ autoFlag,
67
+ nonInteractive,
68
+ jsonFlag,
69
+ });
139
70
  // build bundle and upload assets for a new publish
140
71
  if (!skipBundler) {
141
72
  const bundleSpinner = (0, ora_1.ora)().start('Exporting...');
@@ -154,6 +85,7 @@ class UpdatePublish extends EasCommand_1.default {
154
85
  let unsortedUpdateInfoGroups = {};
155
86
  let uploadedAssetCount = 0;
156
87
  let assetLimitPerUpdateGroup = 0;
88
+ let realizedPlatforms = [];
157
89
  try {
158
90
  const collectedAssets = await (0, publish_1.collectAssetsAsync)(distRoot);
159
91
  const assets = (0, publish_1.filterExportedPlatformsByFlag)(collectedAssets, platformFlag);
@@ -190,20 +122,8 @@ class UpdatePublish extends EasCommand_1.default {
190
122
  assetSpinner.fail('Failed to upload');
191
123
  throw e;
192
124
  }
193
- const truncatedMessage = (0, utils_2.truncateString)(updateMessage, 1024);
194
- if (truncatedMessage !== updateMessage) {
195
- log_1.default.warn('Update message exceeds the allowed 1024 character limit. Truncating message...');
196
- }
197
- const runtimeVersions = await getRuntimeVersionObjectAsync(exp, realizedPlatforms, projectDir);
198
- const runtimeToPlatformMapping = [];
199
- for (const runtime of runtimeVersions) {
200
- const platforms = runtimeVersions
201
- .filter(({ runtimeVersion }) => runtimeVersion === runtime.runtimeVersion)
202
- .map(({ platform }) => platform);
203
- if (!runtimeToPlatformMapping.find(item => item.runtimeVersion === runtime.runtimeVersion)) {
204
- runtimeToPlatformMapping.push({ runtimeVersion: runtime.runtimeVersion, platforms });
205
- }
206
- }
125
+ const runtimeVersions = await (0, publish_1.getRuntimeVersionObjectAsync)(exp, realizedPlatforms, projectDir);
126
+ const runtimeToPlatformMapping = (0, publish_1.getRuntimeToPlatformMappingFromRuntimeVersions)(runtimeVersions);
207
127
  const { branchId, createdBranch } = await (0, queries_1.ensureBranchExistsAsync)(graphqlClient, {
208
128
  appId: projectId,
209
129
  branchName,
@@ -229,7 +149,7 @@ class UpdatePublish extends EasCommand_1.default {
229
149
  branchId,
230
150
  updateInfoGroup: localUpdateInfoGroup,
231
151
  runtimeVersion,
232
- message: truncatedMessage,
152
+ message: updateMessage,
233
153
  gitCommitHash,
234
154
  isGitWorkingTreeDirty,
235
155
  awaitingCodeSigningInfo: !!codeSigningInfo,
@@ -243,7 +163,7 @@ class UpdatePublish extends EasCommand_1.default {
243
163
  log_1.default.log('🔒 Signing updates');
244
164
  const updatesTemp = [...newUpdates];
245
165
  const updateGroupsAndTheirUpdates = updateGroups.map(updateGroup => {
246
- const newUpdates = updatesTemp.splice(0, Object.keys(updateGroup.updateInfoGroup).length);
166
+ const newUpdates = updatesTemp.splice(0, Object.keys((0, nullthrows_1.default)(updateGroup.updateInfoGroup)).length);
247
167
  return {
248
168
  updateGroup,
249
169
  newUpdates,
@@ -256,8 +176,8 @@ class UpdatePublish extends EasCommand_1.default {
256
176
  headers: { accept: 'multipart/mixed' },
257
177
  });
258
178
  const manifestBody = (0, nullthrows_1.default)(await (0, code_signing_1.getManifestBodyAsync)(response));
259
- (0, code_signing_1.checkManifestBodyAgainstUpdateInfoGroup)(manifestBody, (0, nullthrows_1.default)(updateGroup.updateInfoGroup[newUpdate.platform]));
260
- const manifestSignature = (0, code_signing_1.signManifestBody)(manifestBody, codeSigningInfo);
179
+ (0, code_signing_1.checkManifestBodyAgainstUpdateInfoGroup)(manifestBody, (0, nullthrows_1.default)((0, nullthrows_1.default)(updateGroup.updateInfoGroup)[newUpdate.platform]));
180
+ const manifestSignature = (0, code_signing_1.signBody)(manifestBody, codeSigningInfo);
261
181
  await PublishMutation_1.PublishMutation.setCodeSigningInfoAsync(graphqlClient, newUpdate.id, {
262
182
  alg: codeSigningInfo.codeSigningMetadata.alg,
263
183
  keyid: codeSigningInfo.codeSigningMetadata.keyid,
@@ -273,7 +193,7 @@ class UpdatePublish extends EasCommand_1.default {
273
193
  throw e;
274
194
  }
275
195
  if (jsonFlag) {
276
- (0, json_1.printJsonOnlyOutput)((0, utils_2.getUpdateGroupJsonInfo)(newUpdates));
196
+ (0, json_1.printJsonOnlyOutput)((0, utils_1.getUpdateGroupJsonInfo)(newUpdates));
277
197
  }
278
198
  else {
279
199
  if (new Set(newUpdates.map(update => update.group)).size > 1) {
@@ -303,7 +223,7 @@ class UpdatePublish extends EasCommand_1.default {
303
223
  ? [{ label: 'Android update ID', value: newAndroidUpdate.id }]
304
224
  : []),
305
225
  ...(newIosUpdate ? [{ label: 'iOS update ID', value: newIosUpdate.id }] : []),
306
- { label: 'Message', value: truncatedMessage },
226
+ { label: 'Message', value: updateMessage },
307
227
  ...(gitCommitHash
308
228
  ? [
309
229
  {
@@ -396,7 +316,7 @@ UpdatePublish.flags = {
396
316
  char: 'p',
397
317
  options: [
398
318
  // TODO: Add web when it's fully supported
399
- ...exports.defaultPublishPlatforms,
319
+ ...publish_1.defaultPublishPlatforms,
400
320
  'all',
401
321
  ],
402
322
  default: 'all',
@@ -416,28 +336,3 @@ UpdatePublish.contextDefinition = {
416
336
  ..._a.ContextOptions.DynamicProjectConfig,
417
337
  ..._a.ContextOptions.LoggedIn,
418
338
  };
419
- /** Get runtime versions grouped by platform. Runtime version is always `null` on web where the platform is always backwards compatible. */
420
- async function getRuntimeVersionObjectAsync(exp, platforms, projectDir) {
421
- var _b, _c;
422
- for (const platform of platforms) {
423
- if (platform === 'web') {
424
- continue;
425
- }
426
- const isPolicy = typeof ((_c = (_b = exp[platform]) === null || _b === void 0 ? void 0 : _b.runtimeVersion) !== null && _c !== void 0 ? _c : exp.runtimeVersion) === 'object';
427
- if (isPolicy) {
428
- const isManaged = (await (0, workflow_1.resolveWorkflowAsync)(projectDir, platform)) === eas_build_job_1.Workflow.MANAGED;
429
- if (!isManaged) {
430
- throw new Error('Runtime version policies are only supported in the managed workflow. In the bare workflow, runtime version needs to be set manually.');
431
- }
432
- }
433
- }
434
- return [...new Set(platforms)].map(platform => {
435
- if (platform === 'web') {
436
- return { platform: 'web', runtimeVersion: 'UNVERSIONED' };
437
- }
438
- return {
439
- platform,
440
- runtimeVersion: (0, nullthrows_1.default)(config_plugins_1.Updates.getRuntimeVersion(exp, platform), `Unable to determine runtime version for ${platform_1.requestedPlatformDisplayNames[platform]}. ${(0, log_1.learnMore)('https://docs.expo.dev/eas-update/runtime-versions/')}`),
441
- };
442
- });
443
- }
@@ -131,7 +131,7 @@ class UpdateRepublish extends EasCommand_1.default {
131
131
  }
132
132
  exports.default = UpdateRepublish;
133
133
  _a = UpdateRepublish;
134
- UpdateRepublish.description = 'rollback to an existing update';
134
+ UpdateRepublish.description = 'roll back to an existing update';
135
135
  UpdateRepublish.flags = {
136
136
  channel: core_1.Flags.string({
137
137
  description: 'Channel name to select an update to republish from',
@@ -0,0 +1,22 @@
1
+ import EasCommand from '../../commandUtils/EasCommand';
2
+ export default class UpdateRollBackToEmbedded extends EasCommand {
3
+ static hidden: boolean;
4
+ static description: string;
5
+ static flags: {
6
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
7
+ 'non-interactive': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
8
+ branch: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined>;
9
+ channel: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined>;
10
+ message: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined>;
11
+ platform: import("@oclif/core/lib/interfaces").OptionFlag<string>;
12
+ auto: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
13
+ 'private-key-path': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined>;
14
+ };
15
+ static contextDefinition: {
16
+ loggedIn: import("../../commandUtils/context/LoggedInContextField").default;
17
+ getDynamicProjectConfigAsync: import("../../commandUtils/context/DynamicProjectConfigContextField").DynamicProjectConfigContextField;
18
+ };
19
+ runAsync(): Promise<void>;
20
+ private publishRollbacksAsync;
21
+ private sanitizeFlags;
22
+ }
@@ -0,0 +1,253 @@
1
+ "use strict";
2
+ var _a;
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const tslib_1 = require("tslib");
5
+ const core_1 = require("@oclif/core");
6
+ const chalk_1 = tslib_1.__importDefault(require("chalk"));
7
+ const nullthrows_1 = tslib_1.__importDefault(require("nullthrows"));
8
+ const queries_1 = require("../../branch/queries");
9
+ const url_1 = require("../../build/utils/url");
10
+ const queries_2 = require("../../channel/queries");
11
+ const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasCommand"));
12
+ const flags_1 = require("../../commandUtils/flags");
13
+ const pagination_1 = require("../../commandUtils/pagination");
14
+ const fetch_1 = tslib_1.__importDefault(require("../../fetch"));
15
+ const generated_1 = require("../../graphql/generated");
16
+ const PublishMutation_1 = require("../../graphql/mutations/PublishMutation");
17
+ const log_1 = tslib_1.__importStar(require("../../log"));
18
+ const ora_1 = require("../../ora");
19
+ const projectUtils_1 = require("../../project/projectUtils");
20
+ const publish_1 = require("../../project/publish");
21
+ const configure_1 = require("../../update/configure");
22
+ const utils_1 = require("../../update/utils");
23
+ const code_signing_1 = require("../../utils/code-signing");
24
+ const uniqBy_1 = tslib_1.__importDefault(require("../../utils/expodash/uniqBy"));
25
+ const formatFields_1 = tslib_1.__importDefault(require("../../utils/formatFields"));
26
+ const json_1 = require("../../utils/json");
27
+ const statuspageService_1 = require("../../utils/statuspageService");
28
+ const vcs_1 = require("../../vcs");
29
+ class UpdateRollBackToEmbedded extends EasCommand_1.default {
30
+ async runAsync() {
31
+ const { flags: rawFlags } = await this.parse(UpdateRollBackToEmbedded);
32
+ const paginatedQueryOptions = (0, pagination_1.getPaginatedQueryOptions)(rawFlags);
33
+ const { auto: autoFlag, platform: platformFlag, channelName: channelNameArg, updateMessage: updateMessageArg, privateKeyPath, json: jsonFlag, nonInteractive, branchName: branchNameArg, } = this.sanitizeFlags(rawFlags);
34
+ const { getDynamicProjectConfigAsync, loggedIn: { graphqlClient }, } = await this.getContextAsync(UpdateRollBackToEmbedded, {
35
+ nonInteractive,
36
+ });
37
+ if (jsonFlag) {
38
+ (0, json_1.enableJsonOutput)();
39
+ }
40
+ const { exp: expPossiblyWithoutEasUpdateConfigured, projectId, projectDir, } = await getDynamicProjectConfigAsync({
41
+ isPublicConfig: true,
42
+ });
43
+ await (0, statuspageService_1.maybeWarnAboutEasOutagesAsync)(graphqlClient, [generated_1.StatuspageServiceName.EasUpdate]);
44
+ await (0, configure_1.ensureEASUpdateIsConfiguredAsync)(graphqlClient, {
45
+ exp: expPossiblyWithoutEasUpdateConfigured,
46
+ platform: (0, publish_1.getRequestedPlatform)(platformFlag),
47
+ projectDir,
48
+ projectId,
49
+ });
50
+ const { exp } = await getDynamicProjectConfigAsync({ isPublicConfig: true });
51
+ const { exp: expPrivate } = await getDynamicProjectConfigAsync({
52
+ isPublicConfig: false,
53
+ });
54
+ const codeSigningInfo = await (0, code_signing_1.getCodeSigningInfoAsync)(expPrivate, privateKeyPath);
55
+ const branchName = await (0, publish_1.getBranchNameForCommandAsync)({
56
+ graphqlClient,
57
+ projectId,
58
+ channelNameArg,
59
+ branchNameArg,
60
+ autoFlag,
61
+ nonInteractive,
62
+ paginatedQueryOptions,
63
+ });
64
+ const updateMessage = await (0, publish_1.getUpdateMessageForCommandAsync)({
65
+ updateMessageArg,
66
+ autoFlag,
67
+ nonInteractive,
68
+ jsonFlag,
69
+ });
70
+ const realizedPlatforms = platformFlag === 'all' ? publish_1.defaultPublishPlatforms : [platformFlag];
71
+ const { branchId, createdBranch } = await (0, queries_1.ensureBranchExistsAsync)(graphqlClient, {
72
+ appId: projectId,
73
+ branchName,
74
+ });
75
+ if (createdBranch) {
76
+ await (0, queries_2.ensureChannelExistsAsync)(graphqlClient, {
77
+ appId: projectId,
78
+ branchId,
79
+ channelName: branchName,
80
+ });
81
+ }
82
+ log_1.default.withTick(`Channel: ${chalk_1.default.bold(branchName)} pointed at branch: ${chalk_1.default.bold(branchName)}`);
83
+ const vcsClient = (0, vcs_1.getVcsClient)();
84
+ const gitCommitHash = await vcsClient.getCommitHashAsync();
85
+ const isGitWorkingTreeDirty = await vcsClient.hasUncommittedChangesAsync();
86
+ const runtimeVersions = await (0, publish_1.getRuntimeVersionObjectAsync)(exp, realizedPlatforms, projectDir);
87
+ let newUpdates;
88
+ const publishSpinner = (0, ora_1.ora)('Publishing...').start();
89
+ try {
90
+ newUpdates = await this.publishRollbacksAsync({
91
+ graphqlClient,
92
+ isGitWorkingTreeDirty,
93
+ gitCommitHash,
94
+ updateMessage,
95
+ branchId,
96
+ codeSigningInfo,
97
+ runtimeVersions,
98
+ realizedPlatforms,
99
+ });
100
+ publishSpinner.succeed('Published!');
101
+ }
102
+ catch (e) {
103
+ publishSpinner.fail('Failed to publish updates');
104
+ throw e;
105
+ }
106
+ if (jsonFlag) {
107
+ (0, json_1.printJsonOnlyOutput)((0, utils_1.getUpdateGroupJsonInfo)(newUpdates));
108
+ }
109
+ else {
110
+ if (new Set(newUpdates.map(update => update.group)).size > 1) {
111
+ log_1.default.addNewLineIfNone();
112
+ log_1.default.log('👉 Since multiple runtime versions are defined, multiple update groups have been published.');
113
+ }
114
+ log_1.default.addNewLineIfNone();
115
+ for (const runtime of (0, uniqBy_1.default)(runtimeVersions, version => version.runtimeVersion)) {
116
+ const newUpdatesForRuntimeVersion = newUpdates.filter(update => update.runtimeVersion === runtime.runtimeVersion);
117
+ if (newUpdatesForRuntimeVersion.length === 0) {
118
+ throw new Error(`Publish response is missing updates with runtime ${runtime.runtimeVersion}.`);
119
+ }
120
+ const platforms = newUpdatesForRuntimeVersion.map(update => update.platform);
121
+ const newAndroidUpdate = newUpdatesForRuntimeVersion.find(update => update.platform === 'android');
122
+ const newIosUpdate = newUpdatesForRuntimeVersion.find(update => update.platform === 'ios');
123
+ const updateGroupId = newUpdatesForRuntimeVersion[0].group;
124
+ const projectName = exp.slug;
125
+ const accountName = (await (0, projectUtils_1.getOwnerAccountForProjectIdAsync)(graphqlClient, projectId)).name;
126
+ const updateGroupUrl = (0, url_1.getUpdateGroupUrl)(accountName, projectName, updateGroupId);
127
+ const updateGroupLink = (0, log_1.link)(updateGroupUrl, { dim: false });
128
+ log_1.default.log((0, formatFields_1.default)([
129
+ { label: 'Branch', value: branchName },
130
+ { label: 'Runtime version', value: runtime.runtimeVersion },
131
+ { label: 'Platform', value: platforms.join(', ') },
132
+ { label: 'Update group ID', value: updateGroupId },
133
+ ...(newAndroidUpdate
134
+ ? [{ label: 'Android update ID', value: newAndroidUpdate.id }]
135
+ : []),
136
+ ...(newIosUpdate ? [{ label: 'iOS update ID', value: newIosUpdate.id }] : []),
137
+ { label: 'Message', value: updateMessage },
138
+ ...(gitCommitHash
139
+ ? [
140
+ {
141
+ label: 'Commit',
142
+ value: `${gitCommitHash}${isGitWorkingTreeDirty ? '*' : ''}`,
143
+ },
144
+ ]
145
+ : []),
146
+ { label: 'Website link', value: updateGroupLink },
147
+ ]));
148
+ log_1.default.addNewLineIfNone();
149
+ }
150
+ }
151
+ }
152
+ async publishRollbacksAsync({ graphqlClient, isGitWorkingTreeDirty, gitCommitHash, updateMessage, branchId, codeSigningInfo, runtimeVersions, realizedPlatforms, }) {
153
+ const runtimeToPlatformMapping = (0, publish_1.getRuntimeToPlatformMappingFromRuntimeVersions)(runtimeVersions);
154
+ const rollbackInfoGroups = Object.fromEntries(realizedPlatforms.map(platform => [platform, true]));
155
+ // Sort the updates into different groups based on their platform specific runtime versions
156
+ const updateGroups = runtimeToPlatformMapping.map(({ runtimeVersion, platforms }) => {
157
+ const localRollbackInfoGroup = Object.fromEntries(platforms.map(platform => [platform, rollbackInfoGroups[platform]]));
158
+ return {
159
+ branchId,
160
+ rollBackToEmbeddedInfoGroup: localRollbackInfoGroup,
161
+ runtimeVersion,
162
+ message: updateMessage,
163
+ gitCommitHash,
164
+ isGitWorkingTreeDirty,
165
+ awaitingCodeSigningInfo: !!codeSigningInfo,
166
+ };
167
+ });
168
+ const newUpdates = await PublishMutation_1.PublishMutation.publishUpdateGroupAsync(graphqlClient, updateGroups);
169
+ if (codeSigningInfo) {
170
+ log_1.default.log('🔒 Signing roll back');
171
+ const updatesTemp = [...newUpdates];
172
+ const updateGroupsAndTheirUpdates = updateGroups.map(updateGroup => {
173
+ const newUpdates = updatesTemp.splice(0, Object.keys((0, nullthrows_1.default)(updateGroup.rollBackToEmbeddedInfoGroup)).length);
174
+ return {
175
+ updateGroup,
176
+ newUpdates,
177
+ };
178
+ });
179
+ await Promise.all(updateGroupsAndTheirUpdates.map(async ({ newUpdates }) => {
180
+ await Promise.all(newUpdates.map(async (newUpdate) => {
181
+ const response = await (0, fetch_1.default)(newUpdate.manifestPermalink, {
182
+ method: 'GET',
183
+ headers: { accept: 'multipart/mixed' },
184
+ });
185
+ const directiveBody = (0, nullthrows_1.default)(await (0, code_signing_1.getDirectiveBodyAsync)(response));
186
+ (0, code_signing_1.checkDirectiveBodyAgainstUpdateInfoGroup)(directiveBody);
187
+ const directiveSignature = (0, code_signing_1.signBody)(directiveBody, codeSigningInfo);
188
+ await PublishMutation_1.PublishMutation.setCodeSigningInfoAsync(graphqlClient, newUpdate.id, {
189
+ alg: codeSigningInfo.codeSigningMetadata.alg,
190
+ keyid: codeSigningInfo.codeSigningMetadata.keyid,
191
+ sig: directiveSignature,
192
+ });
193
+ }));
194
+ }));
195
+ }
196
+ return newUpdates;
197
+ }
198
+ sanitizeFlags(flags) {
199
+ var _b, _c;
200
+ const nonInteractive = (_b = flags['non-interactive']) !== null && _b !== void 0 ? _b : false;
201
+ const { auto, branch: branchName, channel: channelName, message: updateMessage } = flags;
202
+ if (nonInteractive && !auto && !(updateMessage && (branchName || channelName))) {
203
+ core_1.Errors.error('--branch and --message, or --channel and --message are required when updating in non-interactive mode unless --auto is specified', { exit: 1 });
204
+ }
205
+ return {
206
+ auto,
207
+ branchName,
208
+ channelName,
209
+ updateMessage,
210
+ platform: flags.platform,
211
+ privateKeyPath: flags['private-key-path'],
212
+ nonInteractive,
213
+ json: (_c = flags.json) !== null && _c !== void 0 ? _c : false,
214
+ };
215
+ }
216
+ }
217
+ exports.default = UpdateRollBackToEmbedded;
218
+ _a = UpdateRollBackToEmbedded;
219
+ UpdateRollBackToEmbedded.hidden = true; // until we launch
220
+ UpdateRollBackToEmbedded.description = 'roll back to the embedded update';
221
+ UpdateRollBackToEmbedded.flags = {
222
+ branch: core_1.Flags.string({
223
+ description: 'Branch to publish the rollback to embedded update group on',
224
+ required: false,
225
+ }),
226
+ channel: core_1.Flags.string({
227
+ description: 'Channel that the published rollback to embedded update should affect',
228
+ required: false,
229
+ }),
230
+ message: core_1.Flags.string({
231
+ description: 'A short message describing the rollback to embedded update',
232
+ required: false,
233
+ }),
234
+ platform: core_1.Flags.enum({
235
+ char: 'p',
236
+ options: [...publish_1.defaultPublishPlatforms, 'all'],
237
+ default: 'all',
238
+ required: false,
239
+ }),
240
+ auto: core_1.Flags.boolean({
241
+ description: 'Use the current git branch and commit message for the EAS branch and update message',
242
+ default: false,
243
+ }),
244
+ 'private-key-path': core_1.Flags.string({
245
+ 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.`,
246
+ required: false,
247
+ }),
248
+ ...flags_1.EasNonInteractiveAndJsonFlags,
249
+ };
250
+ UpdateRollBackToEmbedded.contextDefinition = {
251
+ ..._a.ContextOptions.DynamicProjectConfig,
252
+ ..._a.ContextOptions.LoggedIn,
253
+ };
@@ -92,7 +92,7 @@ class IosCredentialsProvider {
92
92
  }
93
93
  }
94
94
  async disablePushNotificationsSetupInEasJsonAsync(ctx) {
95
- const easJsonAccessor = new eas_json_1.EasJsonAccessor(ctx.projectDir);
95
+ const easJsonAccessor = eas_json_1.EasJsonAccessor.fromProjectPath(ctx.projectDir);
96
96
  await easJsonAccessor.readRawJsonAsync();
97
97
  easJsonAccessor.patch(easJsonRawObject => {
98
98
  easJsonRawObject.cli = {
@@ -8,7 +8,7 @@ const prompts_1 = require("../../prompts");
8
8
  class SelectBuildProfileFromEasJson {
9
9
  constructor(projectDir, platform) {
10
10
  this.platform = platform;
11
- this.easJsonAccessor = new eas_json_1.EasJsonAccessor(projectDir);
11
+ this.easJsonAccessor = eas_json_1.EasJsonAccessor.fromProjectPath(projectDir);
12
12
  }
13
13
  async runAsync() {
14
14
  const profileName = await this.getProfileNameFromEasConfigAsync();