eas-cli 2.8.0 → 3.0.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 +152 -53
- package/build/build/build.d.ts +1 -1
- package/build/build/runBuildAndSubmit.js +31 -2
- package/build/commands/build/run.d.ts +0 -1
- package/build/commands/build/run.js +18 -11
- package/build/commands/update/index.js +76 -135
- package/build/commands/update/republish.d.ts +36 -0
- package/build/commands/update/republish.js +218 -0
- package/build/graphql/generated.d.ts +66 -0
- package/build/graphql/types/Update.js +6 -0
- package/build/project/applicationIdentifier.js +6 -2
- package/build/run/android/emulator.js +4 -4
- package/build/run/ios/simulator.js +1 -1
- package/build/run/utils.d.ts +2 -0
- package/build/run/utils.js +20 -0
- package/build/utils/download.d.ts +1 -1
- package/build/utils/download.js +34 -17
- package/build/utils/paths.d.ts +7 -7
- package/build/utils/paths.js +3 -1
- package/oclif.manifest.json +1 -1
- package/package.json +3 -3
|
@@ -3,17 +3,21 @@ var _a;
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const core_1 = require("@oclif/core");
|
|
6
|
+
const assert_1 = tslib_1.__importDefault(require("assert"));
|
|
6
7
|
const fs_extra_1 = require("fs-extra");
|
|
7
|
-
const
|
|
8
|
+
const path_1 = tslib_1.__importDefault(require("path"));
|
|
8
9
|
const queries_1 = require("../../build/queries");
|
|
9
10
|
const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasCommand"));
|
|
10
11
|
const pagination_1 = require("../../commandUtils/pagination");
|
|
11
12
|
const generated_1 = require("../../graphql/generated");
|
|
12
13
|
const BuildQuery_1 = require("../../graphql/queries/BuildQuery");
|
|
14
|
+
const log_1 = tslib_1.__importDefault(require("../../log"));
|
|
13
15
|
const projectUtils_1 = require("../../project/projectUtils");
|
|
14
16
|
const prompts_1 = require("../../prompts");
|
|
15
17
|
const run_1 = require("../../run/run");
|
|
18
|
+
const utils_1 = require("../../run/utils");
|
|
16
19
|
const download_1 = require("../../utils/download");
|
|
20
|
+
const paths_1 = require("../../utils/paths");
|
|
17
21
|
class Run extends EasCommand_1.default {
|
|
18
22
|
async runAsync() {
|
|
19
23
|
const { flags: rawFlags } = await this.parse(Run);
|
|
@@ -52,7 +56,6 @@ class Run extends EasCommand_1.default {
|
|
|
52
56
|
}
|
|
53
57
|
exports.default = Run;
|
|
54
58
|
_a = Run;
|
|
55
|
-
Run.hidden = true;
|
|
56
59
|
Run.description = 'run simulator/emulator builds from eas-cli';
|
|
57
60
|
Run.flags = {
|
|
58
61
|
latest: core_1.Flags.boolean({
|
|
@@ -118,13 +121,8 @@ async function maybeGetBuildAsync(graphqlClient, flags, projectId, paginatedQuer
|
|
|
118
121
|
status: generated_1.BuildStatus.Finished,
|
|
119
122
|
},
|
|
120
123
|
queryOptions: paginatedQueryOptions,
|
|
121
|
-
selectPromptDisabledFunction: build =>
|
|
122
|
-
|
|
123
|
-
return build.platform === generated_1.AppPlatform.Ios
|
|
124
|
-
? false
|
|
125
|
-
: (_d = !((_c = (_b = build.artifacts) === null || _b === void 0 ? void 0 : _b.applicationArchiveUrl) === null || _c === void 0 ? void 0 : _c.endsWith('.apk'))) !== null && _d !== void 0 ? _d : false;
|
|
126
|
-
},
|
|
127
|
-
warningMessage: 'This is not a simulator/emulator build',
|
|
124
|
+
selectPromptDisabledFunction: build => !(0, utils_1.isRunnableOnSimulatorOrEmulator)(build),
|
|
125
|
+
warningMessage: 'Artifacts for this build have expired and are no longer available, or this is not a simulator/emulator build.',
|
|
128
126
|
});
|
|
129
127
|
}
|
|
130
128
|
else if (flags.runArchiveFlags.latest) {
|
|
@@ -141,14 +139,23 @@ async function maybeGetBuildAsync(graphqlClient, flags, projectId, paginatedQuer
|
|
|
141
139
|
return null;
|
|
142
140
|
}
|
|
143
141
|
}
|
|
142
|
+
function getEasBuildRunCachedAppPath(projectId, buildId, platform) {
|
|
143
|
+
return path_1.default.join((0, paths_1.getEasBuildRunCacheDirectoryPath)(), `${projectId}_${buildId}.${platform === generated_1.AppPlatform.Ios ? 'app' : 'apk'}`);
|
|
144
|
+
}
|
|
144
145
|
async function getPathToSimulatorBuildAppAsync(graphqlClient, projectId, flags, queryOptions) {
|
|
145
146
|
var _b, _c;
|
|
146
147
|
const maybeBuild = await maybeGetBuildAsync(graphqlClient, flags, projectId, queryOptions);
|
|
147
148
|
if (maybeBuild) {
|
|
149
|
+
const cachedAppPath = getEasBuildRunCachedAppPath(projectId, maybeBuild.id, flags.selectedPlatform);
|
|
150
|
+
if (await (0, fs_extra_1.pathExists)(cachedAppPath)) {
|
|
151
|
+
log_1.default.newLine();
|
|
152
|
+
log_1.default.log(`Using cached app...`);
|
|
153
|
+
return cachedAppPath;
|
|
154
|
+
}
|
|
148
155
|
if (!((_b = maybeBuild.artifacts) === null || _b === void 0 ? void 0 : _b.applicationArchiveUrl)) {
|
|
149
156
|
throw new Error('Build does not have an application archive url');
|
|
150
157
|
}
|
|
151
|
-
return await (0, download_1.downloadAndMaybeExtractAppAsync)(maybeBuild.artifacts.applicationArchiveUrl, flags.selectedPlatform);
|
|
158
|
+
return await (0, download_1.downloadAndMaybeExtractAppAsync)(maybeBuild.artifacts.applicationArchiveUrl, flags.selectedPlatform, cachedAppPath);
|
|
152
159
|
}
|
|
153
160
|
if (flags.runArchiveFlags.url) {
|
|
154
161
|
return await (0, download_1.downloadAndMaybeExtractAppAsync)(flags.runArchiveFlags.url, flags.selectedPlatform);
|
|
@@ -157,6 +164,6 @@ async function getPathToSimulatorBuildAppAsync(graphqlClient, projectId, flags,
|
|
|
157
164
|
return await (0, download_1.extractAppFromLocalArchiveAsync)(flags.runArchiveFlags.path, flags.selectedPlatform);
|
|
158
165
|
}
|
|
159
166
|
// this should never fail, due to the validation in sanitizeFlagsAsync
|
|
160
|
-
(0,
|
|
167
|
+
(0, assert_1.default)(flags.runArchiveFlags.path);
|
|
161
168
|
return flags.runArchiveFlags.path;
|
|
162
169
|
}
|
|
@@ -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,6 @@ 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 queries_3 = require("../../update/queries");
|
|
32
30
|
const utils_2 = require("../../update/utils");
|
|
33
31
|
const code_signing_1 = require("../../utils/code-signing");
|
|
34
32
|
const uniqBy_1 = tslib_1.__importDefault(require("../../utils/expodash/uniqBy"));
|
|
@@ -53,10 +51,10 @@ function getRequestedPlatform(platform) {
|
|
|
53
51
|
}
|
|
54
52
|
class UpdatePublish extends EasCommand_1.default {
|
|
55
53
|
async runAsync() {
|
|
56
|
-
var _b, _c
|
|
54
|
+
var _b, _c;
|
|
57
55
|
const { flags: rawFlags } = await this.parse(UpdatePublish);
|
|
58
56
|
const paginatedQueryOptions = (0, pagination_1.getPaginatedQueryOptions)(rawFlags);
|
|
59
|
-
let { auto: autoFlag, platform: platformFlag, branchName, updateMessage,
|
|
57
|
+
let { auto: autoFlag, platform: platformFlag, branchName, updateMessage, inputDir, skipBundler, privateKeyPath, json: jsonFlag, nonInteractive, } = this.sanitizeFlags(rawFlags);
|
|
60
58
|
const { getDynamicProjectConfigAsync, loggedIn: { graphqlClient }, } = await this.getContextAsync(UpdatePublish, {
|
|
61
59
|
nonInteractive,
|
|
62
60
|
});
|
|
@@ -90,7 +88,7 @@ class UpdatePublish extends EasCommand_1.default {
|
|
|
90
88
|
try {
|
|
91
89
|
const branch = await (0, queries_1.selectBranchOnAppAsync)(graphqlClient, {
|
|
92
90
|
projectId,
|
|
93
|
-
promptTitle: `Which branch would you like to
|
|
91
|
+
promptTitle: `Which branch would you like to publish on?`,
|
|
94
92
|
displayTextForListItem: updateBranch => `${updateBranch.name} ${chalk_1.default.grey(`- current update: ${(0, utils_2.formatUpdateMessage)(updateBranch.updates[0])}`)}`,
|
|
95
93
|
paginatedQueryOptions,
|
|
96
94
|
});
|
|
@@ -109,131 +107,62 @@ class UpdatePublish extends EasCommand_1.default {
|
|
|
109
107
|
(0, assert_1.default)(branchName, 'Branch name must be specified.');
|
|
110
108
|
}
|
|
111
109
|
}
|
|
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
|
-
}
|
|
110
|
+
if (!updateMessage && autoFlag) {
|
|
111
|
+
updateMessage = (_b = (await (0, vcs_1.getVcsClient)().getLastCommitMessageAsync())) === null || _b === void 0 ? void 0 : _b.trim();
|
|
181
112
|
}
|
|
182
|
-
|
|
183
|
-
if (
|
|
184
|
-
|
|
113
|
+
if (!updateMessage) {
|
|
114
|
+
if (nonInteractive) {
|
|
115
|
+
throw new Error('Must supply --message or use --auto when in non-interactive mode');
|
|
185
116
|
}
|
|
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
|
-
}));
|
|
201
|
-
}
|
|
202
|
-
// build bundle and upload assets for a new publish
|
|
203
|
-
if (!skipBundler) {
|
|
204
|
-
const bundleSpinner = (0, ora_1.ora)().start('Exporting...');
|
|
205
|
-
try {
|
|
206
|
-
await (0, publish_1.buildBundlesAsync)({ projectDir, inputDir, exp, platformFlag });
|
|
207
|
-
bundleSpinner.succeed('Exported bundle(s)');
|
|
208
|
-
}
|
|
209
|
-
catch (e) {
|
|
210
|
-
bundleSpinner.fail('Export failed');
|
|
211
|
-
throw e;
|
|
212
|
-
}
|
|
117
|
+
const validationMessage = 'publish message may not be empty.';
|
|
118
|
+
if (jsonFlag) {
|
|
119
|
+
throw new Error(validationMessage);
|
|
213
120
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
121
|
+
({ updateMessage } = await (0, prompts_1.promptAsync)({
|
|
122
|
+
type: 'text',
|
|
123
|
+
name: 'updateMessage',
|
|
124
|
+
message: `Provide an update message.`,
|
|
125
|
+
initial: (_c = (await (0, vcs_1.getVcsClient)().getLastCommitMessageAsync())) === null || _c === void 0 ? void 0 : _c.trim(),
|
|
126
|
+
validate: (value) => (value ? true : validationMessage),
|
|
127
|
+
}));
|
|
128
|
+
}
|
|
129
|
+
// build bundle and upload assets for a new publish
|
|
130
|
+
if (!skipBundler) {
|
|
131
|
+
const bundleSpinner = (0, ora_1.ora)().start('Exporting...');
|
|
217
132
|
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);
|
|
133
|
+
await (0, publish_1.buildBundlesAsync)({ projectDir, inputDir, exp, platformFlag });
|
|
134
|
+
bundleSpinner.succeed('Exported bundle(s)');
|
|
231
135
|
}
|
|
232
136
|
catch (e) {
|
|
233
|
-
|
|
137
|
+
bundleSpinner.fail('Export failed');
|
|
234
138
|
throw e;
|
|
235
139
|
}
|
|
236
140
|
}
|
|
141
|
+
// After possibly bundling, assert that the input directory can be found.
|
|
142
|
+
const distRoot = await (0, publish_1.resolveInputDirectoryAsync)(inputDir, { skipBundler });
|
|
143
|
+
const assetSpinner = (0, ora_1.ora)().start('Uploading...');
|
|
144
|
+
let unsortedUpdateInfoGroups = {};
|
|
145
|
+
let uploadedAssetCount = 0;
|
|
146
|
+
let assetLimitPerUpdateGroup = 0;
|
|
147
|
+
try {
|
|
148
|
+
const collectedAssets = await (0, publish_1.collectAssetsAsync)(distRoot);
|
|
149
|
+
const assets = (0, publish_1.filterExportedPlatformsByFlag)(collectedAssets, platformFlag);
|
|
150
|
+
realizedPlatforms = Object.keys(assets);
|
|
151
|
+
const uploadResults = await (0, publish_1.uploadAssetsAsync)(graphqlClient, assets, projectId, (totalAssets, missingAssets) => {
|
|
152
|
+
assetSpinner.text = `Uploading (${totalAssets - missingAssets}/${totalAssets})`;
|
|
153
|
+
});
|
|
154
|
+
uploadedAssetCount = uploadResults.uniqueUploadedAssetCount;
|
|
155
|
+
assetLimitPerUpdateGroup = uploadResults.assetLimitPerUpdateGroup;
|
|
156
|
+
unsortedUpdateInfoGroups = await (0, publish_1.buildUnsortedUpdateInfoGroupAsync)(assets, exp);
|
|
157
|
+
const uploadAssetSuccessMessage = uploadedAssetCount
|
|
158
|
+
? `Uploaded ${uploadedAssetCount} ${uploadedAssetCount === 1 ? 'platform' : 'platforms'}`
|
|
159
|
+
: `Uploaded: No changes detected`;
|
|
160
|
+
assetSpinner.succeed(uploadAssetSuccessMessage);
|
|
161
|
+
}
|
|
162
|
+
catch (e) {
|
|
163
|
+
assetSpinner.fail('Failed to upload');
|
|
164
|
+
throw e;
|
|
165
|
+
}
|
|
237
166
|
const truncatedMessage = (0, utils_2.truncateString)(updateMessage, 1024);
|
|
238
167
|
if (truncatedMessage !== updateMessage) {
|
|
239
168
|
log_1.default.warn('Update message exceeds the allowed 1024 character limit. Truncating message...');
|
|
@@ -260,22 +189,22 @@ class UpdatePublish extends EasCommand_1.default {
|
|
|
260
189
|
});
|
|
261
190
|
}
|
|
262
191
|
log_1.default.withTick(`Channel: ${chalk_1.default.bold(branchName)} pointed at branch: ${chalk_1.default.bold(branchName)}`);
|
|
263
|
-
const
|
|
192
|
+
const vcsClient = (0, vcs_1.getVcsClient)();
|
|
193
|
+
const gitCommitHash = await vcsClient.getCommitHashAsync();
|
|
194
|
+
const isGitWorkingTreeDirty = await vcsClient.hasUncommittedChangesAsync();
|
|
264
195
|
// Sort the updates into different groups based on their platform specific runtime versions
|
|
265
196
|
const updateGroups = runtimeToPlatformMapping.map(({ runtimeVersion, platforms }) => {
|
|
266
197
|
const localUpdateInfoGroup = Object.fromEntries(platforms.map(platform => [
|
|
267
198
|
platform,
|
|
268
199
|
unsortedUpdateInfoGroups[platform],
|
|
269
200
|
]));
|
|
270
|
-
if (republish && !oldRuntimeVersion) {
|
|
271
|
-
throw new Error('Cannot find the runtime version of the update group that is being republished.');
|
|
272
|
-
}
|
|
273
201
|
return {
|
|
274
202
|
branchId,
|
|
275
203
|
updateInfoGroup: localUpdateInfoGroup,
|
|
276
|
-
runtimeVersion
|
|
204
|
+
runtimeVersion,
|
|
277
205
|
message: truncatedMessage,
|
|
278
206
|
gitCommitHash,
|
|
207
|
+
isGitWorkingTreeDirty,
|
|
279
208
|
awaitingCodeSigningInfo: !!codeSigningInfo,
|
|
280
209
|
};
|
|
281
210
|
});
|
|
@@ -348,7 +277,14 @@ class UpdatePublish extends EasCommand_1.default {
|
|
|
348
277
|
: []),
|
|
349
278
|
...(newIosUpdate ? [{ label: 'iOS update ID', value: newIosUpdate.id }] : []),
|
|
350
279
|
{ label: 'Message', value: truncatedMessage },
|
|
351
|
-
...(gitCommitHash
|
|
280
|
+
...(gitCommitHash
|
|
281
|
+
? [
|
|
282
|
+
{
|
|
283
|
+
label: 'Commit',
|
|
284
|
+
value: `${gitCommitHash}${isGitWorkingTreeDirty ? '*' : ''}`,
|
|
285
|
+
},
|
|
286
|
+
]
|
|
287
|
+
: []),
|
|
352
288
|
{ label: 'Website link', value: updateGroupLink },
|
|
353
289
|
]));
|
|
354
290
|
log_1.default.addNewLineIfNone();
|
|
@@ -370,17 +306,22 @@ class UpdatePublish extends EasCommand_1.default {
|
|
|
370
306
|
if (nonInteractive && !auto && !(branchName && updateMessage)) {
|
|
371
307
|
core_1.Errors.error('--auto or both --branch and --message are required when updating in non-interactive mode', { exit: 1 });
|
|
372
308
|
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
309
|
+
if (flags.group || flags.republish) {
|
|
310
|
+
// Pick the first flag set that is defined, in this specific order
|
|
311
|
+
const args = [
|
|
312
|
+
['--group', flags.group],
|
|
313
|
+
['--branch', flags.branch],
|
|
314
|
+
].filter(([_, value]) => value)[0];
|
|
315
|
+
log_1.default.newLine();
|
|
316
|
+
log_1.default.warn('The --group and --republish flags are deprecated, use the republish command instead:');
|
|
317
|
+
log_1.default.warn(` ${chalk_1.default.bold([`eas update:republish`, ...(args !== null && args !== void 0 ? args : [])].join(' '))}`);
|
|
318
|
+
log_1.default.newLine();
|
|
319
|
+
core_1.Errors.error('--group and --republish flags are deprecated', { exit: 1 });
|
|
377
320
|
}
|
|
378
321
|
return {
|
|
379
322
|
auto,
|
|
380
323
|
branchName,
|
|
381
324
|
updateMessage,
|
|
382
|
-
groupId,
|
|
383
|
-
republish,
|
|
384
325
|
inputDir: flags['input-dir'],
|
|
385
326
|
skipBundler: flags['skip-bundler'],
|
|
386
327
|
platform: flags.platform,
|
|
@@ -403,11 +344,11 @@ UpdatePublish.flags = {
|
|
|
403
344
|
required: false,
|
|
404
345
|
}),
|
|
405
346
|
republish: core_1.Flags.boolean({
|
|
406
|
-
description: 'Republish an update group',
|
|
347
|
+
description: 'Republish an update group (deprecated, see republish command)',
|
|
407
348
|
exclusive: ['input-dir', 'skip-bundler'],
|
|
408
349
|
}),
|
|
409
350
|
group: core_1.Flags.string({
|
|
410
|
-
description: 'Update group to republish',
|
|
351
|
+
description: 'Update group to republish (deprecated, see republish command)',
|
|
411
352
|
exclusive: ['input-dir', 'skip-bundler'],
|
|
412
353
|
}),
|
|
413
354
|
'input-dir': core_1.Flags.string({
|
|
@@ -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
|
+
}
|