eas-cli 2.9.0 → 3.1.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.
- package/README.md +6 -1209
- package/build/branch/queries.d.ts +2 -1
- package/build/build/ios/credentials.d.ts +3 -0
- package/build/build/ios/credentials.js +16 -1
- package/build/build/ios/graphql.d.ts +4 -1
- package/build/build/ios/graphql.js +2 -1
- package/build/build/ios/prepareJob.d.ts +2 -0
- package/build/build/ios/prepareJob.js +17 -1
- package/build/build/queries.d.ts +6 -0
- package/build/build/queries.js +25 -1
- package/build/channel/errors.d.ts +3 -0
- package/build/channel/errors.js +9 -0
- package/build/channel/queries.js +1 -1
- package/build/commands/branch/delete.js +1 -1
- package/build/commands/branch/view.js +3 -1
- package/build/commands/build/index.d.ts +1 -0
- package/build/commands/build/index.js +2 -0
- package/build/commands/build/resign.d.ts +55 -0
- package/build/commands/build/resign.js +207 -0
- package/build/commands/build/run.js +2 -2
- package/build/commands/channel/edit.js +1 -1
- package/build/commands/update/configure.js +15 -2
- package/build/commands/update/index.d.ts +1 -0
- package/build/commands/update/index.js +85 -139
- package/build/commands/update/list.js +3 -1
- package/build/commands/update/republish.d.ts +36 -0
- package/build/commands/update/republish.js +218 -0
- package/build/devices/queries.js +8 -4
- package/build/graphql/generated.d.ts +199 -5
- package/build/graphql/generated.js +9 -2
- package/build/graphql/mutations/BuildMutation.d.ts +5 -1
- package/build/graphql/mutations/BuildMutation.js +17 -0
- package/build/graphql/queries/ChannelQuery.js +2 -1
- package/build/graphql/types/Update.js +6 -0
- package/build/run/android/emulator.js +3 -3
- package/build/update/configure.d.ts +1 -1
- package/build/update/configure.js +52 -5
- package/build/update/getBranchNameFromChannelNameAsync.d.ts +2 -0
- package/build/update/getBranchNameFromChannelNameAsync.js +45 -0
- package/build/update/queries.js +3 -1
- package/build/utils/queries.d.ts +5 -1
- package/build/utils/queries.js +1 -1
- package/oclif.manifest.json +1 -1
- package/package.json +3 -3
|
@@ -19,7 +19,6 @@ const pagination_1 = require("../../commandUtils/pagination");
|
|
|
19
19
|
const fetch_1 = tslib_1.__importDefault(require("../../fetch"));
|
|
20
20
|
const generated_1 = require("../../graphql/generated");
|
|
21
21
|
const PublishMutation_1 = require("../../graphql/mutations/PublishMutation");
|
|
22
|
-
const UpdateQuery_1 = require("../../graphql/queries/UpdateQuery");
|
|
23
22
|
const log_1 = tslib_1.__importStar(require("../../log"));
|
|
24
23
|
const ora_1 = require("../../ora");
|
|
25
24
|
const platform_1 = require("../../platform");
|
|
@@ -28,7 +27,7 @@ const publish_1 = require("../../project/publish");
|
|
|
28
27
|
const workflow_1 = require("../../project/workflow");
|
|
29
28
|
const prompts_1 = require("../../prompts");
|
|
30
29
|
const configure_1 = require("../../update/configure");
|
|
31
|
-
const
|
|
30
|
+
const getBranchNameFromChannelNameAsync_1 = require("../../update/getBranchNameFromChannelNameAsync");
|
|
32
31
|
const utils_2 = require("../../update/utils");
|
|
33
32
|
const code_signing_1 = require("../../utils/code-signing");
|
|
34
33
|
const uniqBy_1 = tslib_1.__importDefault(require("../../utils/expodash/uniqBy"));
|
|
@@ -53,10 +52,11 @@ function getRequestedPlatform(platform) {
|
|
|
53
52
|
}
|
|
54
53
|
class UpdatePublish extends EasCommand_1.default {
|
|
55
54
|
async runAsync() {
|
|
56
|
-
var _b, _c
|
|
55
|
+
var _b, _c;
|
|
57
56
|
const { flags: rawFlags } = await this.parse(UpdatePublish);
|
|
58
57
|
const paginatedQueryOptions = (0, pagination_1.getPaginatedQueryOptions)(rawFlags);
|
|
59
|
-
let { auto: autoFlag, platform: platformFlag,
|
|
58
|
+
let { auto: autoFlag, platform: platformFlag, channelName, updateMessage, inputDir, skipBundler, privateKeyPath, json: jsonFlag, nonInteractive, } = this.sanitizeFlags(rawFlags);
|
|
59
|
+
let branchName = this.sanitizeFlags(rawFlags).branchName;
|
|
60
60
|
const { getDynamicProjectConfigAsync, loggedIn: { graphqlClient }, } = await this.getContextAsync(UpdatePublish, {
|
|
61
61
|
nonInteractive,
|
|
62
62
|
});
|
|
@@ -70,7 +70,7 @@ class UpdatePublish extends EasCommand_1.default {
|
|
|
70
70
|
isPublicConfig: false,
|
|
71
71
|
});
|
|
72
72
|
await (0, statuspageService_1.maybeWarnAboutEasOutagesAsync)(graphqlClient, [generated_1.StatuspageServiceName.EasUpdate]);
|
|
73
|
-
await (0, configure_1.
|
|
73
|
+
await (0, configure_1.ensureEASUpdateIsConfiguredAsync)(graphqlClient, {
|
|
74
74
|
exp: expPossiblyWithoutEasUpdateConfigured,
|
|
75
75
|
platform: getRequestedPlatform(platformFlag),
|
|
76
76
|
projectDir,
|
|
@@ -79,19 +79,27 @@ class UpdatePublish extends EasCommand_1.default {
|
|
|
79
79
|
const { exp } = await getDynamicProjectConfigAsync();
|
|
80
80
|
const codeSigningInfo = await (0, code_signing_1.getCodeSigningInfoAsync)(expPrivate, privateKeyPath);
|
|
81
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
|
+
}
|
|
82
88
|
if (!branchName) {
|
|
83
89
|
if (autoFlag) {
|
|
84
90
|
branchName = await (0, utils_1.getDefaultBranchNameAsync)();
|
|
85
91
|
}
|
|
86
92
|
else if (nonInteractive) {
|
|
87
|
-
throw new Error('Must supply --branch or
|
|
93
|
+
throw new Error('Must supply --channel, --branch or --auto when in non-interactive mode');
|
|
88
94
|
}
|
|
89
95
|
else {
|
|
90
96
|
try {
|
|
91
97
|
const branch = await (0, queries_1.selectBranchOnAppAsync)(graphqlClient, {
|
|
92
98
|
projectId,
|
|
93
|
-
promptTitle: `Which branch would you like to
|
|
94
|
-
displayTextForListItem: updateBranch =>
|
|
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
|
+
}),
|
|
95
103
|
paginatedQueryOptions,
|
|
96
104
|
});
|
|
97
105
|
branchName = branch.name;
|
|
@@ -109,131 +117,62 @@ class UpdatePublish extends EasCommand_1.default {
|
|
|
109
117
|
(0, assert_1.default)(branchName, 'Branch name must be specified.');
|
|
110
118
|
}
|
|
111
119
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
let uploadedAssetCount = 0;
|
|
115
|
-
let assetLimitPerUpdateGroup = 0;
|
|
116
|
-
if (republish) {
|
|
117
|
-
// If we are republishing, we don't need to worry about building the bundle or uploading the assets.
|
|
118
|
-
// Instead we get the `updateInfoGroup` from the update we wish to republish.
|
|
119
|
-
let updatesToRepublish;
|
|
120
|
-
if (groupId) {
|
|
121
|
-
const updatesByGroup = await UpdateQuery_1.UpdateQuery.viewUpdateGroupAsync(graphqlClient, {
|
|
122
|
-
groupId,
|
|
123
|
-
});
|
|
124
|
-
updatesToRepublish = updatesByGroup;
|
|
125
|
-
}
|
|
126
|
-
else {
|
|
127
|
-
if (nonInteractive) {
|
|
128
|
-
throw new Error('Must supply --group when in non-interactive mode');
|
|
129
|
-
}
|
|
130
|
-
updatesToRepublish = await (0, queries_3.selectUpdateGroupOnBranchAsync)(graphqlClient, {
|
|
131
|
-
projectId,
|
|
132
|
-
branchName,
|
|
133
|
-
paginatedQueryOptions,
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
const updatesToRepublishFilteredByPlatform = updatesToRepublish.filter(
|
|
137
|
-
// Only republish to the specified platforms
|
|
138
|
-
update => platformFlag === 'all' || update.platform === platformFlag);
|
|
139
|
-
if (updatesToRepublishFilteredByPlatform.length === 0) {
|
|
140
|
-
throw new Error(`There are no updates on branch "${branchName}" published for the platform(s) "${platformFlag}" with group ID "${groupId ? groupId : updatesToRepublish[0].group}". Did you mean to publish a new update instead?`);
|
|
141
|
-
}
|
|
142
|
-
let publicationPlatformMessage;
|
|
143
|
-
if (platformFlag === 'all') {
|
|
144
|
-
if (updatesToRepublishFilteredByPlatform.length < exports.defaultPublishPlatforms.length) {
|
|
145
|
-
log_1.default.warn(`You are republishing an update that wasn't published for all platforms.`);
|
|
146
|
-
}
|
|
147
|
-
publicationPlatformMessage = `The republished update will appear on the same platforms it was originally published on: ${updatesToRepublishFilteredByPlatform
|
|
148
|
-
.map(update => update.platform)
|
|
149
|
-
.join(', ')}`;
|
|
150
|
-
}
|
|
151
|
-
else {
|
|
152
|
-
publicationPlatformMessage = `The republished update will appear only on: ${platformFlag}`;
|
|
153
|
-
}
|
|
154
|
-
log_1.default.withTick(publicationPlatformMessage);
|
|
155
|
-
for (const update of updatesToRepublishFilteredByPlatform) {
|
|
156
|
-
const { manifestFragment } = update;
|
|
157
|
-
const platform = update.platform;
|
|
158
|
-
unsortedUpdateInfoGroups[platform] = JSON.parse(manifestFragment);
|
|
159
|
-
}
|
|
160
|
-
realizedPlatforms = updatesToRepublishFilteredByPlatform.map(update => update.platform);
|
|
161
|
-
// These are the same for each member of an update group
|
|
162
|
-
groupId = updatesToRepublishFilteredByPlatform[0].group;
|
|
163
|
-
oldMessage = (_b = updatesToRepublishFilteredByPlatform[0].message) !== null && _b !== void 0 ? _b : '';
|
|
164
|
-
oldRuntimeVersion = updatesToRepublishFilteredByPlatform[0].runtimeVersion;
|
|
165
|
-
if (!updateMessage) {
|
|
166
|
-
if (nonInteractive) {
|
|
167
|
-
throw new Error('Must supply --message when in non-interactive mode');
|
|
168
|
-
}
|
|
169
|
-
const validationMessage = 'publish message may not be empty.';
|
|
170
|
-
if (jsonFlag) {
|
|
171
|
-
throw new Error(validationMessage);
|
|
172
|
-
}
|
|
173
|
-
({ updateMessage } = await (0, prompts_1.promptAsync)({
|
|
174
|
-
type: 'text',
|
|
175
|
-
name: 'updateMessage',
|
|
176
|
-
message: `Provide an update message.`,
|
|
177
|
-
initial: `Republish "${oldMessage}" - group: ${groupId}`,
|
|
178
|
-
validate: (value) => (value ? true : validationMessage),
|
|
179
|
-
}));
|
|
180
|
-
}
|
|
120
|
+
if (!updateMessage && autoFlag) {
|
|
121
|
+
updateMessage = (_b = (await (0, vcs_1.getVcsClient)().getLastCommitMessageAsync())) === null || _b === void 0 ? void 0 : _b.trim();
|
|
181
122
|
}
|
|
182
|
-
|
|
183
|
-
if (
|
|
184
|
-
|
|
123
|
+
if (!updateMessage) {
|
|
124
|
+
if (nonInteractive) {
|
|
125
|
+
throw new Error('Must supply --message or use --auto when in non-interactive mode');
|
|
185
126
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
}
|
|
190
|
-
const validationMessage = 'publish message may not be empty.';
|
|
191
|
-
if (jsonFlag) {
|
|
192
|
-
throw new Error(validationMessage);
|
|
193
|
-
}
|
|
194
|
-
({ updateMessage } = await (0, prompts_1.promptAsync)({
|
|
195
|
-
type: 'text',
|
|
196
|
-
name: 'updateMessage',
|
|
197
|
-
message: `Provide an update message.`,
|
|
198
|
-
initial: (_d = (await (0, vcs_1.getVcsClient)().getLastCommitMessageAsync())) === null || _d === void 0 ? void 0 : _d.trim(),
|
|
199
|
-
validate: (value) => (value ? true : validationMessage),
|
|
200
|
-
}));
|
|
127
|
+
const validationMessage = 'publish message may not be empty.';
|
|
128
|
+
if (jsonFlag) {
|
|
129
|
+
throw new Error(validationMessage);
|
|
201
130
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
}
|
|
214
|
-
// After possibly bundling, assert that the input directory can be found.
|
|
215
|
-
const distRoot = await (0, publish_1.resolveInputDirectoryAsync)(inputDir, { skipBundler });
|
|
216
|
-
const assetSpinner = (0, ora_1.ora)().start('Uploading...');
|
|
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
|
+
}
|
|
139
|
+
// build bundle and upload assets for a new publish
|
|
140
|
+
if (!skipBundler) {
|
|
141
|
+
const bundleSpinner = (0, ora_1.ora)().start('Exporting...');
|
|
217
142
|
try {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
realizedPlatforms = Object.keys(assets);
|
|
221
|
-
const uploadResults = await (0, publish_1.uploadAssetsAsync)(graphqlClient, assets, projectId, (totalAssets, missingAssets) => {
|
|
222
|
-
assetSpinner.text = `Uploading (${totalAssets - missingAssets}/${totalAssets})`;
|
|
223
|
-
});
|
|
224
|
-
uploadedAssetCount = uploadResults.uniqueUploadedAssetCount;
|
|
225
|
-
assetLimitPerUpdateGroup = uploadResults.assetLimitPerUpdateGroup;
|
|
226
|
-
unsortedUpdateInfoGroups = await (0, publish_1.buildUnsortedUpdateInfoGroupAsync)(assets, exp);
|
|
227
|
-
const uploadAssetSuccessMessage = uploadedAssetCount
|
|
228
|
-
? `Uploaded ${uploadedAssetCount} ${uploadedAssetCount === 1 ? 'platform' : 'platforms'}`
|
|
229
|
-
: `Uploaded: No changes detected`;
|
|
230
|
-
assetSpinner.succeed(uploadAssetSuccessMessage);
|
|
143
|
+
await (0, publish_1.buildBundlesAsync)({ projectDir, inputDir, exp, platformFlag });
|
|
144
|
+
bundleSpinner.succeed('Exported bundle(s)');
|
|
231
145
|
}
|
|
232
146
|
catch (e) {
|
|
233
|
-
|
|
147
|
+
bundleSpinner.fail('Export failed');
|
|
234
148
|
throw e;
|
|
235
149
|
}
|
|
236
150
|
}
|
|
151
|
+
// After possibly bundling, assert that the input directory can be found.
|
|
152
|
+
const distRoot = await (0, publish_1.resolveInputDirectoryAsync)(inputDir, { skipBundler });
|
|
153
|
+
const assetSpinner = (0, ora_1.ora)().start('Uploading...');
|
|
154
|
+
let unsortedUpdateInfoGroups = {};
|
|
155
|
+
let uploadedAssetCount = 0;
|
|
156
|
+
let assetLimitPerUpdateGroup = 0;
|
|
157
|
+
try {
|
|
158
|
+
const collectedAssets = await (0, publish_1.collectAssetsAsync)(distRoot);
|
|
159
|
+
const assets = (0, publish_1.filterExportedPlatformsByFlag)(collectedAssets, platformFlag);
|
|
160
|
+
realizedPlatforms = Object.keys(assets);
|
|
161
|
+
const uploadResults = await (0, publish_1.uploadAssetsAsync)(graphqlClient, assets, projectId, (totalAssets, missingAssets) => {
|
|
162
|
+
assetSpinner.text = `Uploading (${totalAssets - missingAssets}/${totalAssets})`;
|
|
163
|
+
});
|
|
164
|
+
uploadedAssetCount = uploadResults.uniqueUploadedAssetCount;
|
|
165
|
+
assetLimitPerUpdateGroup = uploadResults.assetLimitPerUpdateGroup;
|
|
166
|
+
unsortedUpdateInfoGroups = await (0, publish_1.buildUnsortedUpdateInfoGroupAsync)(assets, exp);
|
|
167
|
+
const uploadAssetSuccessMessage = uploadedAssetCount
|
|
168
|
+
? `Uploaded ${uploadedAssetCount} ${uploadedAssetCount === 1 ? 'platform' : 'platforms'}`
|
|
169
|
+
: `Uploaded: No changes detected`;
|
|
170
|
+
assetSpinner.succeed(uploadAssetSuccessMessage);
|
|
171
|
+
}
|
|
172
|
+
catch (e) {
|
|
173
|
+
assetSpinner.fail('Failed to upload');
|
|
174
|
+
throw e;
|
|
175
|
+
}
|
|
237
176
|
const truncatedMessage = (0, utils_2.truncateString)(updateMessage, 1024);
|
|
238
177
|
if (truncatedMessage !== updateMessage) {
|
|
239
178
|
log_1.default.warn('Update message exceeds the allowed 1024 character limit. Truncating message...');
|
|
@@ -269,13 +208,10 @@ class UpdatePublish extends EasCommand_1.default {
|
|
|
269
208
|
platform,
|
|
270
209
|
unsortedUpdateInfoGroups[platform],
|
|
271
210
|
]));
|
|
272
|
-
if (republish && !oldRuntimeVersion) {
|
|
273
|
-
throw new Error('Cannot find the runtime version of the update group that is being republished.');
|
|
274
|
-
}
|
|
275
211
|
return {
|
|
276
212
|
branchId,
|
|
277
213
|
updateInfoGroup: localUpdateInfoGroup,
|
|
278
|
-
runtimeVersion
|
|
214
|
+
runtimeVersion,
|
|
279
215
|
message: truncatedMessage,
|
|
280
216
|
gitCommitHash,
|
|
281
217
|
isGitWorkingTreeDirty,
|
|
@@ -376,21 +312,27 @@ class UpdatePublish extends EasCommand_1.default {
|
|
|
376
312
|
sanitizeFlags(flags) {
|
|
377
313
|
var _b, _c;
|
|
378
314
|
const nonInteractive = (_b = flags['non-interactive']) !== null && _b !== void 0 ? _b : false;
|
|
379
|
-
const { auto, branch: branchName, message: updateMessage } = flags;
|
|
380
|
-
if (nonInteractive && !auto && !(branchName && updateMessage)) {
|
|
381
|
-
core_1.Errors.error('--auto or both --branch and --message are required when updating in non-interactive mode', { exit: 1 });
|
|
315
|
+
const { auto, branch: branchName, channel: channelName, message: updateMessage } = flags;
|
|
316
|
+
if (nonInteractive && !auto && !(branchName && channelName && updateMessage)) {
|
|
317
|
+
core_1.Errors.error('--auto or both --channel or --branch and --message are required when updating in non-interactive mode', { exit: 1 });
|
|
382
318
|
}
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
319
|
+
if (flags.group || flags.republish) {
|
|
320
|
+
// Pick the first flag set that is defined, in this specific order
|
|
321
|
+
const args = [
|
|
322
|
+
['--group', flags.group],
|
|
323
|
+
['--branch', flags.branch],
|
|
324
|
+
].filter(([_, value]) => value)[0];
|
|
325
|
+
log_1.default.newLine();
|
|
326
|
+
log_1.default.warn('The --group and --republish flags are deprecated, use the republish command instead:');
|
|
327
|
+
log_1.default.warn(` ${chalk_1.default.bold([`eas update:republish`, ...(args !== null && args !== void 0 ? args : [])].join(' '))}`);
|
|
328
|
+
log_1.default.newLine();
|
|
329
|
+
core_1.Errors.error('--group and --republish flags are deprecated', { exit: 1 });
|
|
387
330
|
}
|
|
388
331
|
return {
|
|
389
332
|
auto,
|
|
390
333
|
branchName,
|
|
334
|
+
channelName,
|
|
391
335
|
updateMessage,
|
|
392
|
-
groupId,
|
|
393
|
-
republish,
|
|
394
336
|
inputDir: flags['input-dir'],
|
|
395
337
|
skipBundler: flags['skip-bundler'],
|
|
396
338
|
platform: flags.platform,
|
|
@@ -408,16 +350,20 @@ UpdatePublish.flags = {
|
|
|
408
350
|
description: 'Branch to publish the update group on',
|
|
409
351
|
required: false,
|
|
410
352
|
}),
|
|
353
|
+
channel: core_1.Flags.string({
|
|
354
|
+
description: 'Channel that the published update should affect',
|
|
355
|
+
required: false,
|
|
356
|
+
}),
|
|
411
357
|
message: core_1.Flags.string({
|
|
412
358
|
description: 'A short message describing the update',
|
|
413
359
|
required: false,
|
|
414
360
|
}),
|
|
415
361
|
republish: core_1.Flags.boolean({
|
|
416
|
-
description: 'Republish an update group',
|
|
362
|
+
description: 'Republish an update group (deprecated, see republish command)',
|
|
417
363
|
exclusive: ['input-dir', 'skip-bundler'],
|
|
418
364
|
}),
|
|
419
365
|
group: core_1.Flags.string({
|
|
420
|
-
description: 'Update group to republish',
|
|
366
|
+
description: 'Update group to republish (deprecated, see republish command)',
|
|
421
367
|
exclusive: ['input-dir', 'skip-bundler'],
|
|
422
368
|
}),
|
|
423
369
|
'input-dir': core_1.Flags.string({
|
|
@@ -39,7 +39,9 @@ class UpdateList extends EasCommand_1.default {
|
|
|
39
39
|
const selectedBranch = await (0, queries_1.selectBranchOnAppAsync)(graphqlClient, {
|
|
40
40
|
projectId,
|
|
41
41
|
promptTitle: 'Which branch would you like to view?',
|
|
42
|
-
displayTextForListItem: updateBranch =>
|
|
42
|
+
displayTextForListItem: updateBranch => ({
|
|
43
|
+
title: updateBranch.name,
|
|
44
|
+
}),
|
|
43
45
|
paginatedQueryOptions:
|
|
44
46
|
// discard limit and offset because this query is not those flag's intended target
|
|
45
47
|
{
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Platform } from '@expo/config';
|
|
2
|
+
import EasCommand from '../../commandUtils/EasCommand';
|
|
3
|
+
declare type UpdateRepublishRawFlags = {
|
|
4
|
+
branch?: string;
|
|
5
|
+
group?: string;
|
|
6
|
+
message?: string;
|
|
7
|
+
platform: string;
|
|
8
|
+
'non-interactive': boolean;
|
|
9
|
+
json?: boolean;
|
|
10
|
+
};
|
|
11
|
+
declare type UpdateRepublishFlags = {
|
|
12
|
+
branchName?: string;
|
|
13
|
+
groupId?: string;
|
|
14
|
+
updateMessage?: string;
|
|
15
|
+
platform: Platform[];
|
|
16
|
+
nonInteractive: boolean;
|
|
17
|
+
json: boolean;
|
|
18
|
+
};
|
|
19
|
+
export default class UpdateRepublish extends EasCommand {
|
|
20
|
+
static description: string;
|
|
21
|
+
static flags: {
|
|
22
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
23
|
+
'non-interactive': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
24
|
+
branch: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined>;
|
|
25
|
+
group: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined>;
|
|
26
|
+
message: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined>;
|
|
27
|
+
platform: import("@oclif/core/lib/interfaces").OptionFlag<string>;
|
|
28
|
+
};
|
|
29
|
+
static contextDefinition: {
|
|
30
|
+
loggedIn: import("../../commandUtils/context/LoggedInContextField").default;
|
|
31
|
+
projectConfig: import("../../commandUtils/context/ProjectConfigContextField").default;
|
|
32
|
+
};
|
|
33
|
+
runAsync(): Promise<void>;
|
|
34
|
+
sanitizeFlags(rawFlags: UpdateRepublishRawFlags): UpdateRepublishFlags;
|
|
35
|
+
}
|
|
36
|
+
export {};
|
|
@@ -0,0 +1,218 @@
|
|
|
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 url_1 = require("../../build/utils/url");
|
|
7
|
+
const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasCommand"));
|
|
8
|
+
const flags_1 = require("../../commandUtils/flags");
|
|
9
|
+
const pagination_1 = require("../../commandUtils/pagination");
|
|
10
|
+
const PublishMutation_1 = require("../../graphql/mutations/PublishMutation");
|
|
11
|
+
const UpdateQuery_1 = require("../../graphql/queries/UpdateQuery");
|
|
12
|
+
const log_1 = tslib_1.__importStar(require("../../log"));
|
|
13
|
+
const ora_1 = require("../../ora");
|
|
14
|
+
const projectUtils_1 = require("../../project/projectUtils");
|
|
15
|
+
const prompts_1 = require("../../prompts");
|
|
16
|
+
const queries_1 = require("../../update/queries");
|
|
17
|
+
const utils_1 = require("../../update/utils");
|
|
18
|
+
const formatFields_1 = tslib_1.__importDefault(require("../../utils/formatFields"));
|
|
19
|
+
const json_1 = require("../../utils/json");
|
|
20
|
+
const defaultRepublishPlatforms = ['android', 'ios'];
|
|
21
|
+
class UpdateRepublish extends EasCommand_1.default {
|
|
22
|
+
async runAsync() {
|
|
23
|
+
const { flags: rawFlags } = await this.parse(UpdateRepublish);
|
|
24
|
+
const flags = this.sanitizeFlags(rawFlags);
|
|
25
|
+
const { projectConfig: { exp, projectId }, loggedIn: { graphqlClient }, } = await this.getContextAsync(UpdateRepublish, {
|
|
26
|
+
nonInteractive: flags.nonInteractive,
|
|
27
|
+
});
|
|
28
|
+
if (flags.json) {
|
|
29
|
+
(0, json_1.enableJsonOutput)();
|
|
30
|
+
}
|
|
31
|
+
const existingUpdates = await getOrAskUpdatesAsync(graphqlClient, projectId, flags);
|
|
32
|
+
const updatesToPublish = existingUpdates.filter(update => flags.platform.includes(update.platform));
|
|
33
|
+
if (existingUpdates.length === 0) {
|
|
34
|
+
throw new Error(`There are no published updates found`);
|
|
35
|
+
}
|
|
36
|
+
if (updatesToPublish.length === 0) {
|
|
37
|
+
throw new Error(`There are no updates on branch "${existingUpdates[0].branchName}" published for the platform(s) "${rawFlags.platform}" with group ID "${flags.groupId ? flags.groupId : updatesToPublish[0].groupId}". Did you mean to publish a new update instead?`);
|
|
38
|
+
}
|
|
39
|
+
if (rawFlags.platform === 'all') {
|
|
40
|
+
log_1.default.withTick(`The republished update will appear only on: ${rawFlags.platform}`);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
const platformsFromUpdates = updatesToPublish.map(update => update.platform);
|
|
44
|
+
if (platformsFromUpdates.length < defaultRepublishPlatforms.length) {
|
|
45
|
+
log_1.default.warn(`You are republishing an update that wasn't published for all platforms.`);
|
|
46
|
+
}
|
|
47
|
+
log_1.default.withTick(`The republished update will appear on the same platforms it was originally published on: ${platformsFromUpdates.join(', ')}`);
|
|
48
|
+
}
|
|
49
|
+
// This command only republishes a single update group
|
|
50
|
+
// The update group properties are the same for all updates
|
|
51
|
+
const { branchId, branchName, runtimeVersion } = updatesToPublish[0];
|
|
52
|
+
const updateMessage = await getOrAskUpdateMessageAsync(updatesToPublish, flags);
|
|
53
|
+
// If codesigning was created for the original update, we need to add it to the republish
|
|
54
|
+
const shouldRepublishWithCodesigning = updatesToPublish.some(update => update.codeSigningInfo);
|
|
55
|
+
if (shouldRepublishWithCodesigning) {
|
|
56
|
+
log_1.default.withTick(`The republished update will be signed with the same codesigning as the original update.`);
|
|
57
|
+
}
|
|
58
|
+
const publishIndicator = (0, ora_1.ora)('Republishing...').start();
|
|
59
|
+
let updatesRepublished;
|
|
60
|
+
try {
|
|
61
|
+
updatesRepublished = await PublishMutation_1.PublishMutation.publishUpdateGroupAsync(graphqlClient, [
|
|
62
|
+
{
|
|
63
|
+
branchId,
|
|
64
|
+
runtimeVersion,
|
|
65
|
+
message: updateMessage,
|
|
66
|
+
updateInfoGroup: Object.fromEntries(updatesToPublish.map(update => [update.platform, JSON.parse(update.manifestFragment)])),
|
|
67
|
+
gitCommitHash: updatesToPublish[0].gitCommitHash,
|
|
68
|
+
awaitingCodeSigningInfo: shouldRepublishWithCodesigning,
|
|
69
|
+
},
|
|
70
|
+
]);
|
|
71
|
+
if (shouldRepublishWithCodesigning) {
|
|
72
|
+
const codeSigningByPlatform = Object.fromEntries(updatesToPublish.map(update => [update.platform, update.codeSigningInfo]));
|
|
73
|
+
await Promise.all(updatesRepublished.map(async (update) => {
|
|
74
|
+
const codeSigning = codeSigningByPlatform[update.platform];
|
|
75
|
+
if (codeSigning) {
|
|
76
|
+
await PublishMutation_1.PublishMutation.setCodeSigningInfoAsync(graphqlClient, update.id, codeSigning);
|
|
77
|
+
}
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
publishIndicator.succeed('Republished update');
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
publishIndicator.fail('Failed to republish update');
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
if (flags.json) {
|
|
87
|
+
return (0, json_1.printJsonOnlyOutput)(updatesRepublished);
|
|
88
|
+
}
|
|
89
|
+
const updatesRepublishedByPlatform = Object.fromEntries(updatesRepublished.map(update => [update.platform, update]));
|
|
90
|
+
const updateGroupUrl = (0, url_1.getUpdateGroupUrl)((await (0, projectUtils_1.getOwnerAccountForProjectIdAsync)(graphqlClient, projectId)).name, exp.slug, updatesRepublished[0].group);
|
|
91
|
+
log_1.default.addNewLineIfNone();
|
|
92
|
+
log_1.default.log((0, formatFields_1.default)([
|
|
93
|
+
{ label: 'Branch', value: branchName },
|
|
94
|
+
{ label: 'Runtime version', value: updatesRepublished[0].runtimeVersion },
|
|
95
|
+
{ label: 'Platform', value: updatesRepublished.map(update => update.platform).join(', ') },
|
|
96
|
+
{ label: 'Update Group ID', value: updatesRepublished[0].id },
|
|
97
|
+
...(updatesRepublishedByPlatform.android
|
|
98
|
+
? [{ label: 'Android update ID', value: updatesRepublishedByPlatform.android.id }]
|
|
99
|
+
: []),
|
|
100
|
+
...(updatesRepublishedByPlatform.ios
|
|
101
|
+
? [{ label: 'iOS update ID', value: updatesRepublishedByPlatform.ios.id }]
|
|
102
|
+
: []),
|
|
103
|
+
{ label: 'Message', value: updateMessage },
|
|
104
|
+
{ label: 'Website link', value: (0, log_1.link)(updateGroupUrl, { dim: false }) },
|
|
105
|
+
]));
|
|
106
|
+
}
|
|
107
|
+
sanitizeFlags(rawFlags) {
|
|
108
|
+
var _b;
|
|
109
|
+
const branchName = rawFlags.branch;
|
|
110
|
+
const groupId = rawFlags.group;
|
|
111
|
+
if (!branchName && !groupId) {
|
|
112
|
+
throw new Error('Either --branch or --group must be specified');
|
|
113
|
+
}
|
|
114
|
+
const platform = rawFlags.platform === 'all' ? defaultRepublishPlatforms : [rawFlags.platform];
|
|
115
|
+
return {
|
|
116
|
+
branchName,
|
|
117
|
+
groupId,
|
|
118
|
+
platform,
|
|
119
|
+
updateMessage: rawFlags.message,
|
|
120
|
+
json: (_b = rawFlags.json) !== null && _b !== void 0 ? _b : false,
|
|
121
|
+
nonInteractive: rawFlags['non-interactive'],
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
exports.default = UpdateRepublish;
|
|
126
|
+
_a = UpdateRepublish;
|
|
127
|
+
UpdateRepublish.description = 'rollback to an existing update';
|
|
128
|
+
UpdateRepublish.flags = {
|
|
129
|
+
branch: core_1.Flags.string({
|
|
130
|
+
description: 'Branch name to select an update to republish from',
|
|
131
|
+
exclusive: ['group'],
|
|
132
|
+
}),
|
|
133
|
+
group: core_1.Flags.string({
|
|
134
|
+
description: 'Update group ID to republish',
|
|
135
|
+
exclusive: ['branch'],
|
|
136
|
+
}),
|
|
137
|
+
message: core_1.Flags.string({
|
|
138
|
+
description: 'Short message describing the republished update',
|
|
139
|
+
required: false,
|
|
140
|
+
}),
|
|
141
|
+
platform: core_1.Flags.enum({
|
|
142
|
+
char: 'p',
|
|
143
|
+
options: [...defaultRepublishPlatforms, 'all'],
|
|
144
|
+
default: 'all',
|
|
145
|
+
required: false,
|
|
146
|
+
}),
|
|
147
|
+
...flags_1.EasNonInteractiveAndJsonFlags,
|
|
148
|
+
};
|
|
149
|
+
UpdateRepublish.contextDefinition = {
|
|
150
|
+
..._a.ContextOptions.ProjectConfig,
|
|
151
|
+
..._a.ContextOptions.LoggedIn,
|
|
152
|
+
};
|
|
153
|
+
/** Retrieve the update group from either the update group id, or select from branch name. */
|
|
154
|
+
async function getOrAskUpdatesAsync(graphqlClient, projectId, flags) {
|
|
155
|
+
if (flags.groupId) {
|
|
156
|
+
const updateGroups = await UpdateQuery_1.UpdateQuery.viewUpdateGroupAsync(graphqlClient, {
|
|
157
|
+
groupId: flags.groupId,
|
|
158
|
+
});
|
|
159
|
+
return updateGroups.map(group => ({
|
|
160
|
+
...group,
|
|
161
|
+
groupId: group.group,
|
|
162
|
+
branchId: group.branch.id,
|
|
163
|
+
branchName: group.branch.name,
|
|
164
|
+
}));
|
|
165
|
+
}
|
|
166
|
+
if (flags.branchName) {
|
|
167
|
+
return await askUpdatesFromBranchNameAsync(graphqlClient, {
|
|
168
|
+
...flags,
|
|
169
|
+
branchName: flags.branchName,
|
|
170
|
+
projectId,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
throw new Error('Must supply --group or --branch');
|
|
174
|
+
}
|
|
175
|
+
/** Ask the user which update needs to be republished by branch name, this requires interactive mode */
|
|
176
|
+
async function askUpdatesFromBranchNameAsync(graphqlClient, { projectId, branchName, json, nonInteractive, }) {
|
|
177
|
+
if (nonInteractive) {
|
|
178
|
+
throw new Error('Must supply --group when in non-interactive mode');
|
|
179
|
+
}
|
|
180
|
+
const updateGroups = await (0, queries_1.selectUpdateGroupOnBranchAsync)(graphqlClient, {
|
|
181
|
+
projectId,
|
|
182
|
+
branchName,
|
|
183
|
+
paginatedQueryOptions: (0, pagination_1.getPaginatedQueryOptions)({ json, 'non-interactive': nonInteractive }),
|
|
184
|
+
});
|
|
185
|
+
return updateGroups.map(group => ({
|
|
186
|
+
...group,
|
|
187
|
+
groupId: group.id,
|
|
188
|
+
branchId: group.branch.id,
|
|
189
|
+
branchName: group.branch.name,
|
|
190
|
+
}));
|
|
191
|
+
}
|
|
192
|
+
/** Get or ask the user for the update (group) message for the republish */
|
|
193
|
+
async function getOrAskUpdateMessageAsync(updates, flags) {
|
|
194
|
+
if (flags.updateMessage) {
|
|
195
|
+
return sanitizeUpdateMessage(flags.updateMessage);
|
|
196
|
+
}
|
|
197
|
+
if (flags.nonInteractive || flags.json) {
|
|
198
|
+
throw new Error('Must supply --message when in non-interactive mode');
|
|
199
|
+
}
|
|
200
|
+
// This command only uses a single update group to republish, meaning these values are always identical
|
|
201
|
+
const oldGroupId = updates[0].groupId;
|
|
202
|
+
const oldUpdateMessage = updates[0].message;
|
|
203
|
+
const { updateMessage } = await (0, prompts_1.promptAsync)({
|
|
204
|
+
type: 'text',
|
|
205
|
+
name: 'updateMessage',
|
|
206
|
+
message: 'Provide an update message.',
|
|
207
|
+
initial: `Republish "${oldUpdateMessage}" - group: ${oldGroupId}`,
|
|
208
|
+
validate: (value) => (value ? true : 'Update message may not be empty.'),
|
|
209
|
+
});
|
|
210
|
+
return sanitizeUpdateMessage(updateMessage);
|
|
211
|
+
}
|
|
212
|
+
function sanitizeUpdateMessage(updateMessage) {
|
|
213
|
+
if (updateMessage !== (0, utils_1.truncateString)(updateMessage, 1024)) {
|
|
214
|
+
log_1.default.warn('Update message exceeds the allowed 1024 character limit, truncated update message.');
|
|
215
|
+
return (0, utils_1.truncateString)(updateMessage, 1024);
|
|
216
|
+
}
|
|
217
|
+
return updateMessage;
|
|
218
|
+
}
|
package/build/devices/queries.js
CHANGED
|
@@ -29,9 +29,11 @@ async function selectAppleTeamOnAccountAsync(graphqlClient, { accountName, selec
|
|
|
29
29
|
}),
|
|
30
30
|
promptOptions: {
|
|
31
31
|
title: selectionPromptTitle,
|
|
32
|
-
createDisplayTextForSelectionPromptListItem: appleTeam =>
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
createDisplayTextForSelectionPromptListItem: appleTeam => ({
|
|
33
|
+
title: appleTeam.appleTeamName
|
|
34
|
+
? `${appleTeam.appleTeamName} (ID: ${appleTeam.appleTeamIdentifier})`
|
|
35
|
+
: appleTeam.appleTeamIdentifier,
|
|
36
|
+
}),
|
|
35
37
|
getIdentifierForQueryItem: appleTeam => appleTeam.id,
|
|
36
38
|
},
|
|
37
39
|
});
|
|
@@ -59,7 +61,9 @@ async function selectAppleDeviceOnAppleTeamAsync(graphqlClient, { accountName, a
|
|
|
59
61
|
}),
|
|
60
62
|
promptOptions: {
|
|
61
63
|
title: selectionPromptTitle,
|
|
62
|
-
createDisplayTextForSelectionPromptListItem: appleDevice => (
|
|
64
|
+
createDisplayTextForSelectionPromptListItem: appleDevice => ({
|
|
65
|
+
title: (0, DeviceUtils_1.formatDeviceLabel)(appleDevice),
|
|
66
|
+
}),
|
|
63
67
|
getIdentifierForQueryItem: appleTeam => appleTeam.id,
|
|
64
68
|
},
|
|
65
69
|
});
|