eas-cli 0.48.2 → 0.51.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 +137 -43
- package/build/build/build.d.ts +6 -2
- package/build/build/build.js +191 -104
- package/build/build/local.js +1 -1
- package/build/build/runBuildAndSubmit.js +5 -1
- package/build/build/utils/printBuildInfo.js +1 -2
- package/build/commands/update/index.d.ts +1 -0
- package/build/commands/update/index.js +27 -3
- package/build/credentials/android/actions/CreateGoogleServiceAccountKey.js +24 -9
- package/build/credentials/context.js +5 -0
- package/build/credentials/ios/actions/AscApiKeyUtils.js +0 -1
- package/build/credentials/ios/actions/ConfigureProvisioningProfile.js +1 -1
- package/build/credentials/ios/actions/CreateProvisioningProfile.js +1 -1
- package/build/credentials/ios/appstore/AppStoreApi.d.ts +5 -1
- package/build/credentials/ios/appstore/AppStoreApi.js +38 -15
- package/build/credentials/ios/appstore/ascApiKey.d.ts +21 -5
- package/build/credentials/ios/appstore/ascApiKey.js +28 -12
- package/build/credentials/ios/appstore/authenticate.d.ts +9 -18
- package/build/credentials/ios/appstore/authenticate.js +43 -3
- package/build/credentials/ios/appstore/authenticateTypes.d.ts +42 -0
- package/build/credentials/ios/appstore/authenticateTypes.js +16 -0
- package/build/credentials/ios/appstore/capabilityIdentifiers.d.ts +2 -0
- package/build/credentials/ios/appstore/capabilityIdentifiers.js +9 -0
- package/build/credentials/ios/appstore/contractMessages.d.ts +3 -0
- package/build/credentials/ios/appstore/contractMessages.js +12 -0
- package/build/credentials/ios/appstore/distributionCertificate.d.ts +1 -1
- package/build/credentials/ios/appstore/ensureAppExists.d.ts +2 -2
- package/build/credentials/ios/appstore/ensureAppExists.js +12 -5
- package/build/credentials/ios/appstore/provisioningProfile.d.ts +1 -1
- package/build/credentials/ios/appstore/provisioningProfile.js +6 -0
- package/build/credentials/ios/appstore/provisioningProfileAdhoc.d.ts +1 -1
- package/build/credentials/ios/appstore/provisioningProfileAdhoc.js +17 -2
- package/build/credentials/ios/appstore/pushKey.d.ts +16 -4
- package/build/credentials/ios/appstore/pushKey.js +20 -8
- package/build/credentials/ios/appstore/resolveCredentials.d.ts +10 -1
- package/build/credentials/ios/appstore/resolveCredentials.js +125 -3
- package/build/credentials/ios/utils/authType.d.ts +4 -0
- package/build/credentials/ios/utils/authType.js +8 -0
- package/build/fetch.d.ts +1 -1
- package/build/fetch.js +10 -7
- package/build/graphql/client.js +1 -1
- package/build/graphql/generated.d.ts +73 -0
- package/build/graphql/generated.js +16 -1
- package/build/graphql/types/Build.js +4 -0
- package/build/project/ios/target.js +37 -0
- package/build/project/publish.js +2 -1
- package/build/submit/android/ServiceAccountSource.js +1 -1
- package/build/submit/ios/AppProduce.d.ts +0 -1
- package/build/submit/ios/AppProduce.js +5 -6
- package/build/submit/ios/AppSpecificPasswordSource.js +2 -2
- package/build/submit/utils/errors.js +6 -2
- package/build/utils/code-signing.d.ts +0 -5
- package/build/utils/code-signing.js +16 -65
- package/oclif.manifest.json +1 -1
- package/package.json +14 -14
package/build/build/build.js
CHANGED
|
@@ -4,9 +4,12 @@ exports.waitForBuildEndAsync = exports.prepareBuildRequestForPlatformAsync = voi
|
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const eas_build_job_1 = require("@expo/eas-build-job");
|
|
6
6
|
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
7
|
+
const cli_progress_1 = tslib_1.__importDefault(require("cli-progress"));
|
|
7
8
|
const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
|
|
9
|
+
const nullthrows_1 = tslib_1.__importDefault(require("nullthrows"));
|
|
8
10
|
const common_1 = require("../analytics/common");
|
|
9
11
|
const events_1 = require("../analytics/events");
|
|
12
|
+
const api_1 = require("../api");
|
|
10
13
|
const generated_1 = require("../graphql/generated");
|
|
11
14
|
const BuildQuery_1 = require("../graphql/queries/BuildQuery");
|
|
12
15
|
const log_1 = tslib_1.__importStar(require("../log"));
|
|
@@ -54,7 +57,6 @@ async function prepareBuildRequestForPlatformAsync(builder) {
|
|
|
54
57
|
credentials: credentialsResult === null || credentialsResult === void 0 ? void 0 : credentialsResult.credentials,
|
|
55
58
|
});
|
|
56
59
|
return async () => {
|
|
57
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
58
60
|
if (ctx.localBuildOptions.enable) {
|
|
59
61
|
await (0, local_1.runLocalBuildAsync)(job, ctx.localBuildOptions);
|
|
60
62
|
return undefined;
|
|
@@ -64,31 +66,35 @@ async function prepareBuildRequestForPlatformAsync(builder) {
|
|
|
64
66
|
return await sendBuildRequestAsync(builder, job, metadata);
|
|
65
67
|
}
|
|
66
68
|
catch (error) {
|
|
67
|
-
|
|
68
|
-
log_1.default.error('EAS Build API has changed, please upgrade to the latest eas-cli version.');
|
|
69
|
-
throw new Error('Build request failed.');
|
|
70
|
-
}
|
|
71
|
-
else if (((_f = (_e = (_d = error === null || error === void 0 ? void 0 : error.graphQLErrors) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.extensions) === null || _f === void 0 ? void 0 : _f.errorCode) === 'EAS_BUILD_DOWN_FOR_MAINTENANCE') {
|
|
72
|
-
log_1.default.error('EAS Build is down for maintenance, please try again later. Check https://status.expo.dev/ for updates.');
|
|
73
|
-
throw new Error('Build request failed.');
|
|
74
|
-
}
|
|
75
|
-
else if (((_j = (_h = (_g = error === null || error === void 0 ? void 0 : error.graphQLErrors) === null || _g === void 0 ? void 0 : _g[0]) === null || _h === void 0 ? void 0 : _h.extensions) === null || _j === void 0 ? void 0 : _j.errorCode) === 'EAS_BUILD_FREE_TIER_DISABLED') {
|
|
76
|
-
log_1.default.error('EAS Build free tier is temporarily disabled, please try again later. Check https://status.expo.dev/ for updates.');
|
|
77
|
-
throw new Error('Build request failed.');
|
|
78
|
-
}
|
|
79
|
-
else if (((_m = (_l = (_k = error === null || error === void 0 ? void 0 : error.graphQLErrors) === null || _k === void 0 ? void 0 : _k[0]) === null || _l === void 0 ? void 0 : _l.extensions) === null || _m === void 0 ? void 0 : _m.errorCode) === 'EAS_BUILD_TOO_MANY_PENDING_BUILDS') {
|
|
80
|
-
log_1.default.error(`You have already reached the maximum number of pending ${platform_1.requestedPlatformDisplayNames[job.platform]} builds for your account. Try again later.`);
|
|
81
|
-
throw new Error('Build request failed.');
|
|
82
|
-
}
|
|
83
|
-
else if (error === null || error === void 0 ? void 0 : error.graphQLErrors) {
|
|
84
|
-
log_1.default.error('Build request failed. Make sure you are using the latest eas-cli version. If the problem persists, please report the issue.');
|
|
85
|
-
}
|
|
86
|
-
throw error;
|
|
69
|
+
handleBuildRequestError(error, job.platform);
|
|
87
70
|
}
|
|
88
71
|
}
|
|
89
72
|
};
|
|
90
73
|
}
|
|
91
74
|
exports.prepareBuildRequestForPlatformAsync = prepareBuildRequestForPlatformAsync;
|
|
75
|
+
function handleBuildRequestError(error, platform) {
|
|
76
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
77
|
+
if (((_c = (_b = (_a = error === null || error === void 0 ? void 0 : error.graphQLErrors) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.extensions) === null || _c === void 0 ? void 0 : _c.errorCode) === 'TURTLE_DEPRECATED_JOB_FORMAT') {
|
|
78
|
+
log_1.default.error('EAS Build API has changed, please upgrade to the latest eas-cli version.');
|
|
79
|
+
throw new Error('Build request failed.');
|
|
80
|
+
}
|
|
81
|
+
else if (((_f = (_e = (_d = error === null || error === void 0 ? void 0 : error.graphQLErrors) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.extensions) === null || _f === void 0 ? void 0 : _f.errorCode) === 'EAS_BUILD_DOWN_FOR_MAINTENANCE') {
|
|
82
|
+
log_1.default.error('EAS Build is down for maintenance, please try again later. Check https://status.expo.dev/ for updates.');
|
|
83
|
+
throw new Error('Build request failed.');
|
|
84
|
+
}
|
|
85
|
+
else if (((_j = (_h = (_g = error === null || error === void 0 ? void 0 : error.graphQLErrors) === null || _g === void 0 ? void 0 : _g[0]) === null || _h === void 0 ? void 0 : _h.extensions) === null || _j === void 0 ? void 0 : _j.errorCode) === 'EAS_BUILD_FREE_TIER_DISABLED') {
|
|
86
|
+
log_1.default.error('EAS Build free tier is temporarily disabled, please try again later. Check https://status.expo.dev/ for updates.');
|
|
87
|
+
throw new Error('Build request failed.');
|
|
88
|
+
}
|
|
89
|
+
else if (((_m = (_l = (_k = error === null || error === void 0 ? void 0 : error.graphQLErrors) === null || _k === void 0 ? void 0 : _k[0]) === null || _l === void 0 ? void 0 : _l.extensions) === null || _m === void 0 ? void 0 : _m.errorCode) === 'EAS_BUILD_TOO_MANY_PENDING_BUILDS') {
|
|
90
|
+
log_1.default.error(`You have already reached the maximum number of pending ${platform_1.requestedPlatformDisplayNames[platform]} builds for your account. Try again later.`);
|
|
91
|
+
throw new Error('Build request failed.');
|
|
92
|
+
}
|
|
93
|
+
else if (error === null || error === void 0 ? void 0 : error.graphQLErrors) {
|
|
94
|
+
log_1.default.error('Build request failed. Make sure you are using the latest eas-cli version. If the problem persists, please report the issue.');
|
|
95
|
+
}
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
92
98
|
async function uploadProjectAsync(ctx) {
|
|
93
99
|
let projectTarballPath;
|
|
94
100
|
try {
|
|
@@ -130,96 +136,177 @@ async function sendBuildRequestAsync(builder, job, metadata) {
|
|
|
130
136
|
trackingCtx: ctx.trackingCtx,
|
|
131
137
|
});
|
|
132
138
|
}
|
|
133
|
-
async function waitForBuildEndAsync(
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
139
|
+
async function waitForBuildEndAsync({ buildIds, accountName }, {
|
|
140
|
+
// 2 hours (max build time limit) + 10 minutes (possible queue time)
|
|
141
|
+
timeoutSec = 2 * 60 * 60 + 10 * 60, intervalSec = 10, } = {}) {
|
|
142
|
+
const b = `build${buildIds.length > 1 ? 's' : ''}`;
|
|
143
|
+
log_1.default.log(`Waiting for ${b} to complete. You can press Ctrl+C to exit.`);
|
|
144
|
+
const spinner = (0, ora_1.ora)(`Waiting for ${b} to complete.`).start();
|
|
145
|
+
const endTime = new Date().getTime() + timeoutSec * 1000;
|
|
146
|
+
while (new Date().getTime() <= endTime) {
|
|
147
|
+
const builds = await getBuildsSafelyAsync(buildIds);
|
|
148
|
+
const { refetch } = builds.length === 1
|
|
149
|
+
? await handleSingleBuildProgressAsync({ build: builds[0], accountName }, { spinner })
|
|
150
|
+
: await handleMultipleBuildsProgressAsync({ builds }, { spinner });
|
|
151
|
+
if (!refetch) {
|
|
152
|
+
return builds;
|
|
153
|
+
}
|
|
154
|
+
await (0, promise_1.sleepAsync)(intervalSec * 1000);
|
|
155
|
+
}
|
|
156
|
+
spinner.fail('Timed out');
|
|
157
|
+
throw new Error('Timeout reached! It is taking longer than expected to finish the build, aborting...');
|
|
158
|
+
}
|
|
159
|
+
exports.waitForBuildEndAsync = waitForBuildEndAsync;
|
|
160
|
+
async function getBuildsSafelyAsync(buildIds) {
|
|
161
|
+
const promises = buildIds.map(async (buildId) => {
|
|
162
|
+
try {
|
|
163
|
+
return await BuildQuery_1.BuildQuery.byIdAsync(buildId, { useCache: false });
|
|
164
|
+
}
|
|
165
|
+
catch (err) {
|
|
166
|
+
log_1.default.debug('Failed to fetch the build status', err);
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
return await Promise.all(promises);
|
|
171
|
+
}
|
|
172
|
+
let queueProgressBarStarted = false;
|
|
173
|
+
const queueProgressBar = new cli_progress_1.default.SingleBar({ format: '|{bar}| {estimatedWaitTime}' }, cli_progress_1.default.Presets.rect);
|
|
174
|
+
async function handleSingleBuildProgressAsync({ build, accountName }, { spinner }) {
|
|
175
|
+
if (build === null) {
|
|
176
|
+
spinner.text = 'Could not fetch the build status. Check your network connection.';
|
|
177
|
+
return { refetch: true };
|
|
178
|
+
}
|
|
179
|
+
if (queueProgressBarStarted && (build === null || build === void 0 ? void 0 : build.status) && build.status !== generated_1.BuildStatus.InQueue) {
|
|
180
|
+
if (build.status === generated_1.BuildStatus.InProgress) {
|
|
181
|
+
queueProgressBar.update(queueProgressBar.getTotal(), {
|
|
182
|
+
estimatedWaitTime: '',
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
queueProgressBar.stop();
|
|
186
|
+
log_1.default.newLine();
|
|
187
|
+
queueProgressBarStarted = false;
|
|
188
|
+
spinner.start('Build is about to start');
|
|
189
|
+
}
|
|
190
|
+
switch (build.status) {
|
|
191
|
+
case generated_1.BuildStatus.Finished:
|
|
192
|
+
spinner.succeed('Build finished');
|
|
193
|
+
return { refetch: false };
|
|
194
|
+
case generated_1.BuildStatus.New:
|
|
195
|
+
spinner.text = `Build is waiting to enter the queue. Check your concurrency limit at ${chalk_1.default.underline(formatAccountSubscriptionsUrl(accountName))}.`;
|
|
196
|
+
break;
|
|
197
|
+
case generated_1.BuildStatus.InQueue: {
|
|
198
|
+
spinner.text = 'Build queued...';
|
|
199
|
+
const progressBarPayload = typeof build.estimatedWaitTimeLeftSeconds === 'number'
|
|
200
|
+
? { estimatedWaitTime: formatEstimatedWaitTime(build.estimatedWaitTimeLeftSeconds) }
|
|
201
|
+
: { estimatedWaitTime: '' };
|
|
202
|
+
if (!queueProgressBarStarted &&
|
|
203
|
+
typeof build.initialQueuePosition === 'number' &&
|
|
204
|
+
typeof build.queuePosition === 'number') {
|
|
205
|
+
spinner.stopAndPersist();
|
|
206
|
+
if (build.priority !== generated_1.BuildPriority.High) {
|
|
207
|
+
log_1.default.newLine();
|
|
208
|
+
log_1.default.log('Start builds sooner in the priority queue.');
|
|
209
|
+
log_1.default.log(`Sign up for EAS Production or Enterprise at ${chalk_1.default.underline(formatAccountSubscriptionsUrl(accountName))}`);
|
|
179
210
|
}
|
|
211
|
+
log_1.default.newLine();
|
|
212
|
+
log_1.default.log('Waiting in queue');
|
|
213
|
+
queueProgressBar.start(build.initialQueuePosition + 1, build.initialQueuePosition - build.queuePosition + 1, progressBarPayload);
|
|
214
|
+
queueProgressBarStarted = true;
|
|
180
215
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
spinner.text = 'Could not fetch the build status. Check your network connection.';
|
|
184
|
-
}
|
|
216
|
+
if (typeof build.queuePosition === 'number') {
|
|
217
|
+
queueProgressBar.update(build.queuePosition, progressBarPayload);
|
|
185
218
|
}
|
|
219
|
+
break;
|
|
186
220
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
return
|
|
221
|
+
case generated_1.BuildStatus.Canceled:
|
|
222
|
+
spinner.fail('Build canceled');
|
|
223
|
+
return { refetch: false };
|
|
224
|
+
case generated_1.BuildStatus.InProgress:
|
|
225
|
+
spinner.text = 'Build in progress...';
|
|
226
|
+
break;
|
|
227
|
+
case generated_1.BuildStatus.Errored:
|
|
228
|
+
spinner.fail('Build failed');
|
|
229
|
+
if (build.error) {
|
|
230
|
+
return { refetch: false };
|
|
197
231
|
}
|
|
198
232
|
else {
|
|
199
|
-
|
|
200
|
-
const inQueue = builds.filter(build => (build === null || build === void 0 ? void 0 : build.status) === generated_1.BuildStatus.InQueue).length;
|
|
201
|
-
const inProgress = builds.filter(build => (build === null || build === void 0 ? void 0 : build.status) === generated_1.BuildStatus.InProgress).length;
|
|
202
|
-
const errored = builds.filter(build => (build === null || build === void 0 ? void 0 : build.status) === generated_1.BuildStatus.Errored).length;
|
|
203
|
-
const finished = builds.filter(build => (build === null || build === void 0 ? void 0 : build.status) === generated_1.BuildStatus.Finished).length;
|
|
204
|
-
const canceled = builds.filter(build => (build === null || build === void 0 ? void 0 : build.status) === generated_1.BuildStatus.Canceled).length;
|
|
205
|
-
const unknown = builds.length - newBuilds - inQueue - inProgress - errored - finished - canceled;
|
|
206
|
-
spinner.text = [
|
|
207
|
-
newBuilds && `Builds created: ${newBuilds}`,
|
|
208
|
-
inQueue && `Builds in queue: ${inQueue}`,
|
|
209
|
-
inProgress && `Builds in progress: ${inProgress}`,
|
|
210
|
-
canceled && `Builds canceled: ${canceled}`,
|
|
211
|
-
errored && chalk_1.default.red(`Builds failed: ${errored}`),
|
|
212
|
-
finished && chalk_1.default.green(`Builds finished: ${finished}`),
|
|
213
|
-
unknown && chalk_1.default.red(`Builds with unknown status: ${unknown}`),
|
|
214
|
-
]
|
|
215
|
-
.filter(i => i)
|
|
216
|
-
.join('\t');
|
|
233
|
+
throw new Error('Standalone build failed!');
|
|
217
234
|
}
|
|
235
|
+
default:
|
|
236
|
+
spinner.warn('Unknown status');
|
|
237
|
+
throw new Error(`Unknown build status: ${build.status} - aborting!`);
|
|
238
|
+
}
|
|
239
|
+
return { refetch: true };
|
|
240
|
+
}
|
|
241
|
+
const statusToDisplayName = {
|
|
242
|
+
[generated_1.BuildStatus.New]: 'waiting to enter the queue (concurrency limit reached)',
|
|
243
|
+
[generated_1.BuildStatus.InQueue]: 'in queue',
|
|
244
|
+
[generated_1.BuildStatus.InProgress]: 'in progress',
|
|
245
|
+
[generated_1.BuildStatus.Canceled]: 'canceled',
|
|
246
|
+
[generated_1.BuildStatus.Finished]: 'finished',
|
|
247
|
+
[generated_1.BuildStatus.Errored]: 'failed',
|
|
248
|
+
};
|
|
249
|
+
const platforms = [generated_1.AppPlatform.Android, generated_1.AppPlatform.Ios];
|
|
250
|
+
async function handleMultipleBuildsProgressAsync({ builds: maybeBuilds }, { spinner }) {
|
|
251
|
+
const buildCount = maybeBuilds.length;
|
|
252
|
+
const builds = maybeBuilds.filter(isBuildFragment);
|
|
253
|
+
const allFinished = builds.filter(build => build.status === generated_1.BuildStatus.Finished).length === buildCount;
|
|
254
|
+
const allSettled = builds.filter(build => [generated_1.BuildStatus.Finished, generated_1.BuildStatus.Errored, generated_1.BuildStatus.Canceled].includes(build.status)).length === buildCount;
|
|
255
|
+
if (allSettled) {
|
|
256
|
+
if (allFinished) {
|
|
257
|
+
spinner.succeed(formatSettledBuildsText(builds));
|
|
218
258
|
}
|
|
219
|
-
|
|
220
|
-
|
|
259
|
+
else {
|
|
260
|
+
spinner.fail(formatSettledBuildsText(builds));
|
|
261
|
+
}
|
|
262
|
+
return { refetch: false };
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
spinner.text = formatPendingBuildsText(builds);
|
|
266
|
+
return { refetch: true };
|
|
221
267
|
}
|
|
222
|
-
spinner.warn('Timed out');
|
|
223
|
-
throw new Error('Timeout reached! It is taking longer than expected to finish the build, aborting...');
|
|
224
268
|
}
|
|
225
|
-
|
|
269
|
+
function formatSettledBuildsText(builds) {
|
|
270
|
+
return platforms
|
|
271
|
+
.map(platform => {
|
|
272
|
+
const build = (0, nullthrows_1.default)(builds.find(build => build.platform === platform), `Build for platform ${platform} must be defined in this context`);
|
|
273
|
+
return `${platform_1.appPlatformEmojis[platform]} ${platform_1.appPlatformDisplayNames[platform]} build - status: ${chalk_1.default.bold(statusToDisplayName[build.status])}`;
|
|
274
|
+
})
|
|
275
|
+
.join('\n ');
|
|
276
|
+
}
|
|
277
|
+
function formatPendingBuildsText(builds) {
|
|
278
|
+
return platforms
|
|
279
|
+
.map(platform => {
|
|
280
|
+
const build = builds.find(build => build.platform === platform);
|
|
281
|
+
const status = build ? statusToDisplayName[build.status] : 'unknown';
|
|
282
|
+
let extraInfo = '';
|
|
283
|
+
if ((build === null || build === void 0 ? void 0 : build.status) === generated_1.BuildStatus.InQueue &&
|
|
284
|
+
typeof build.initialQueuePosition === 'number' &&
|
|
285
|
+
typeof build.queuePosition === 'number') {
|
|
286
|
+
const percent = Math.floor(((build.initialQueuePosition - build.queuePosition + 1) /
|
|
287
|
+
(build.initialQueuePosition + 1)) *
|
|
288
|
+
100);
|
|
289
|
+
const estimatedWaitTime = typeof build.estimatedWaitTimeLeftSeconds === 'number'
|
|
290
|
+
? ` - ${formatEstimatedWaitTime(build.estimatedWaitTimeLeftSeconds)}`
|
|
291
|
+
: '';
|
|
292
|
+
extraInfo = ` - queue progress: ${chalk_1.default.bold(`${percent}%`)}${estimatedWaitTime}`;
|
|
293
|
+
}
|
|
294
|
+
return `${platform_1.appPlatformEmojis[platform]} ${platform_1.appPlatformDisplayNames[platform]} build - status: ${chalk_1.default.bold(status)}${extraInfo}`;
|
|
295
|
+
})
|
|
296
|
+
.join('\n ');
|
|
297
|
+
}
|
|
298
|
+
function isBuildFragment(maybeBuild) {
|
|
299
|
+
return maybeBuild !== null;
|
|
300
|
+
}
|
|
301
|
+
function formatEstimatedWaitTime(estimatedWaitTimeLeftSeconds) {
|
|
302
|
+
if (estimatedWaitTimeLeftSeconds < 5 * 60) {
|
|
303
|
+
return 'starting soon...';
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
const n = Math.floor(estimatedWaitTimeLeftSeconds / (10 * 60)) + 1;
|
|
307
|
+
return `starting in about ${n}0 minutes...`;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
function formatAccountSubscriptionsUrl(accountName) {
|
|
311
|
+
return new URL(`/accounts/${accountName}/settings/subscriptions`, (0, api_1.getExpoWebsiteBaseUrl)()).toString();
|
|
312
|
+
}
|
package/build/build/local.js
CHANGED
|
@@ -6,7 +6,7 @@ const spawn_async_1 = tslib_1.__importDefault(require("@expo/spawn-async"));
|
|
|
6
6
|
const semver_1 = tslib_1.__importDefault(require("semver"));
|
|
7
7
|
const ora_1 = require("../ora");
|
|
8
8
|
const PLUGIN_PACKAGE_NAME = 'eas-cli-local-build-plugin';
|
|
9
|
-
const PLUGIN_PACKAGE_VERSION = '0.0.
|
|
9
|
+
const PLUGIN_PACKAGE_VERSION = '0.0.74';
|
|
10
10
|
async function runLocalBuildAsync(job, options) {
|
|
11
11
|
var _a;
|
|
12
12
|
const { command, args } = await getCommandAndArgsAsync(job);
|
|
@@ -98,7 +98,11 @@ async function runBuildAndSubmitAsync(projectDir, flags) {
|
|
|
98
98
|
}
|
|
99
99
|
return;
|
|
100
100
|
}
|
|
101
|
-
const
|
|
101
|
+
const { accountName } = Object.values(buildCtxByPlatform)[0];
|
|
102
|
+
const builds = await (0, build_2.waitForBuildEndAsync)({
|
|
103
|
+
buildIds: startedBuilds.map(({ build }) => build.id),
|
|
104
|
+
accountName,
|
|
105
|
+
});
|
|
102
106
|
(0, printBuildInfo_1.printBuildResults)(builds, flags.json);
|
|
103
107
|
const haveAllBuildsFailedOrCanceled = builds.every(build => (build === null || build === void 0 ? void 0 : build.status) && [generated_1.BuildStatus.Errored, generated_1.BuildStatus.Canceled].includes(build === null || build === void 0 ? void 0 : build.status));
|
|
104
108
|
if (haveAllBuildsFailedOrCanceled || !flags.autoSubmit) {
|
|
@@ -82,8 +82,7 @@ function printDeprecationWarnings(deprecationInfo) {
|
|
|
82
82
|
log_1.default.warn(deprecationInfo.message);
|
|
83
83
|
}
|
|
84
84
|
else if (deprecationInfo.type === generated_1.EasBuildDeprecationInfoType.UserFacing) {
|
|
85
|
-
log_1.default.warn('This command is using API that soon will be deprecated
|
|
86
|
-
log_1.default.warn('There might be some changes necessary to your project config, latest eas-cli will provide more specific error messages.');
|
|
85
|
+
log_1.default.warn('This command is using API that soon will be deprecated.');
|
|
87
86
|
log_1.default.warn(deprecationInfo.message);
|
|
88
87
|
}
|
|
89
88
|
else {
|
|
@@ -14,6 +14,7 @@ export default class UpdatePublish extends EasCommand {
|
|
|
14
14
|
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
15
15
|
auto: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
16
16
|
'private-key-path': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined>;
|
|
17
|
+
'non-interactive': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
17
18
|
};
|
|
18
19
|
runAsync(): Promise<void>;
|
|
19
20
|
}
|
|
@@ -89,7 +89,7 @@ async function ensureBranchExistsAsync({ appId, name: branchName, }) {
|
|
|
89
89
|
class UpdatePublish extends EasCommand_1.default {
|
|
90
90
|
async runAsync() {
|
|
91
91
|
var _a, _b, _c;
|
|
92
|
-
let { flags: { branch: branchName, json: jsonFlag, auto: autoFlag, message, republish, group, 'input-dir': inputDir, 'skip-bundler': skipBundler, platform, 'private-key-path': privateKeyPath, }, } = await this.parse(UpdatePublish);
|
|
92
|
+
let { flags: { branch: branchName, json: jsonFlag, auto: autoFlag, message, republish, group, 'input-dir': inputDir, 'skip-bundler': skipBundler, platform, 'private-key-path': privateKeyPath, 'non-interactive': nonInteractive, }, } = await this.parse(UpdatePublish);
|
|
93
93
|
if (jsonFlag) {
|
|
94
94
|
(0, json_1.enableJsonOutput)();
|
|
95
95
|
}
|
|
@@ -101,8 +101,16 @@ class UpdatePublish extends EasCommand_1.default {
|
|
|
101
101
|
skipSDKVersionRequirement: true,
|
|
102
102
|
isPublicConfig: true,
|
|
103
103
|
});
|
|
104
|
-
const
|
|
105
|
-
|
|
104
|
+
const { exp: expPrivate } = (0, config_1.getConfig)(projectDir, {
|
|
105
|
+
skipSDKVersionRequirement: true,
|
|
106
|
+
isPublicConfig: false,
|
|
107
|
+
});
|
|
108
|
+
const codeSigningInfo = await (0, code_signing_1.getCodeSigningInfoAsync)(expPrivate, privateKeyPath);
|
|
109
|
+
const hasExpoUpdates = (0, projectUtils_1.isExpoUpdatesInstalledOrAvailable)(projectDir, exp.sdkVersion);
|
|
110
|
+
if (!hasExpoUpdates && nonInteractive) {
|
|
111
|
+
core_1.Errors.error(`${chalk_1.default.bold('expo-updates')} must already be installed when executing in non-interactive mode`, { exit: 1 });
|
|
112
|
+
}
|
|
113
|
+
if (!hasExpoUpdates) {
|
|
106
114
|
const install = await (0, prompts_1.confirmAsync)({
|
|
107
115
|
message: `You are creating an update which requires ${chalk_1.default.bold('expo-updates')} to be installed in your app.\n Do you want EAS CLI to install it for you?`,
|
|
108
116
|
instructions: 'The command will abort unless you agree.',
|
|
@@ -125,6 +133,9 @@ class UpdatePublish extends EasCommand_1.default {
|
|
|
125
133
|
`branch-${Math.random().toString(36).substr(2, 4)}`;
|
|
126
134
|
}
|
|
127
135
|
if (!branchName) {
|
|
136
|
+
if (nonInteractive) {
|
|
137
|
+
throw new Error('Must supply --branch or use --auto when in non-interactive mode');
|
|
138
|
+
}
|
|
128
139
|
const validationMessage = 'Branch name may not be empty.';
|
|
129
140
|
if (jsonFlag) {
|
|
130
141
|
throw new Error(validationMessage);
|
|
@@ -164,6 +175,9 @@ class UpdatePublish extends EasCommand_1.default {
|
|
|
164
175
|
updatesToRepublish = await getUpdateGroupAsync({ group });
|
|
165
176
|
}
|
|
166
177
|
else {
|
|
178
|
+
if (nonInteractive) {
|
|
179
|
+
throw new Error('Must supply --group when in non-interactive mode');
|
|
180
|
+
}
|
|
167
181
|
// Drop into interactive mode if the user has not specified an update group to republish.
|
|
168
182
|
if (jsonFlag) {
|
|
169
183
|
throw new Error('You must specify the update group to republish.');
|
|
@@ -212,6 +226,9 @@ class UpdatePublish extends EasCommand_1.default {
|
|
|
212
226
|
oldMessage = (_a = updatesToRepublishFilteredByPlatform[0].message) !== null && _a !== void 0 ? _a : '';
|
|
213
227
|
oldRuntimeVersion = updatesToRepublishFilteredByPlatform[0].runtimeVersion;
|
|
214
228
|
if (!message) {
|
|
229
|
+
if (nonInteractive) {
|
|
230
|
+
throw new Error('Must supply --message when in non-interactive mode');
|
|
231
|
+
}
|
|
215
232
|
const validationMessage = 'publish message may not be empty.';
|
|
216
233
|
if (jsonFlag) {
|
|
217
234
|
throw new Error(validationMessage);
|
|
@@ -230,6 +247,9 @@ class UpdatePublish extends EasCommand_1.default {
|
|
|
230
247
|
message = (_b = (await (0, vcs_1.getVcsClient)().getLastCommitMessageAsync())) === null || _b === void 0 ? void 0 : _b.trim();
|
|
231
248
|
}
|
|
232
249
|
if (!message) {
|
|
250
|
+
if (nonInteractive) {
|
|
251
|
+
throw new Error('Must supply --message or use --auto when in non-interactive mode');
|
|
252
|
+
}
|
|
233
253
|
const validationMessage = 'publish message may not be empty.';
|
|
234
254
|
if (jsonFlag) {
|
|
235
255
|
throw new Error(validationMessage);
|
|
@@ -402,6 +422,10 @@ UpdatePublish.flags = {
|
|
|
402
422
|
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.`,
|
|
403
423
|
required: false,
|
|
404
424
|
}),
|
|
425
|
+
'non-interactive': core_1.Flags.boolean({
|
|
426
|
+
default: false,
|
|
427
|
+
description: 'Run command in non-interactive mode',
|
|
428
|
+
}),
|
|
405
429
|
};
|
|
406
430
|
async function getRuntimeVersionObjectAsync(exp, platformFlag, projectDir) {
|
|
407
431
|
var _a, _b;
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.CreateGoogleServiceAccountKey = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
-
const
|
|
5
|
+
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
6
|
+
const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
|
|
7
|
+
const log_1 = tslib_1.__importStar(require("../../../log"));
|
|
6
8
|
const prompts_1 = require("../../../prompts");
|
|
7
9
|
const googleServiceAccountKey_1 = require("../utils/googleServiceAccountKey");
|
|
8
10
|
class CreateGoogleServiceAccountKey {
|
|
@@ -33,15 +35,28 @@ class CreateGoogleServiceAccountKey {
|
|
|
33
35
|
if (detectedPath) {
|
|
34
36
|
return detectedPath;
|
|
35
37
|
}
|
|
36
|
-
|
|
37
|
-
{
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
log_1.default.log(`${chalk_1.default.bold('A Google Service Account JSON key is required to upload your app to Google Play Store')}.\n` +
|
|
39
|
+
`If you're not sure what this is or how to create one, ${(0, log_1.learnMore)('https://expo.fyi/creating-google-service-account', { learnMoreMessage: 'learn more' })}`);
|
|
40
|
+
const { filePath } = await (0, prompts_1.promptAsync)({
|
|
41
|
+
name: 'filePath',
|
|
42
|
+
message: 'Path to Google Service Account file:',
|
|
43
|
+
initial: 'api-0000000000000000000-111111-aaaaaabbbbbb.json',
|
|
44
|
+
type: 'text',
|
|
45
|
+
// eslint-disable-next-line async-protect/async-suffix
|
|
46
|
+
validate: async (filePath) => {
|
|
47
|
+
try {
|
|
48
|
+
const stats = await fs_extra_1.default.stat(filePath);
|
|
49
|
+
if (stats.isFile()) {
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
return 'Input is not a file.';
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return 'File does not exist.';
|
|
56
|
+
}
|
|
42
57
|
},
|
|
43
|
-
|
|
44
|
-
return
|
|
58
|
+
});
|
|
59
|
+
return filePath;
|
|
45
60
|
}
|
|
46
61
|
}
|
|
47
62
|
exports.CreateGoogleServiceAccountKey = CreateGoogleServiceAccountKey;
|
|
@@ -12,6 +12,7 @@ const User_1 = require("../user/User");
|
|
|
12
12
|
const AndroidGraphqlClient = tslib_1.__importStar(require("./android/api/GraphqlClient"));
|
|
13
13
|
const IosGraphqlClient = tslib_1.__importStar(require("./ios/api/GraphqlClient"));
|
|
14
14
|
const AppStoreApi_1 = tslib_1.__importDefault(require("./ios/appstore/AppStoreApi"));
|
|
15
|
+
const authenticateTypes_1 = require("./ios/appstore/authenticateTypes");
|
|
15
16
|
class CredentialsContext {
|
|
16
17
|
constructor(options) {
|
|
17
18
|
var _a, _b;
|
|
@@ -73,6 +74,10 @@ class CredentialsContext {
|
|
|
73
74
|
if (this.nonInteractive) {
|
|
74
75
|
return;
|
|
75
76
|
}
|
|
77
|
+
if (this.appStore.defaultAuthenticationMode === authenticateTypes_1.AuthenticationMode.API_KEY) {
|
|
78
|
+
await this.appStore.ensureAuthenticatedAsync();
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
76
81
|
log_1.default.log(chalk_1.default.green('If you provide your Apple account credentials we will be able to generate all necessary build credentials and fully validate them.'));
|
|
77
82
|
log_1.default.log(chalk_1.default.green('This is optional, but without Apple account access you will need to provide all the missing values manually and we can only run minimal validation on them.'));
|
|
78
83
|
const confirm = await (0, prompts_1.confirmAsync)({
|
|
@@ -70,7 +70,6 @@ async function provideOrGenerateAscApiKeyAsync(ctx, purpose) {
|
|
|
70
70
|
}
|
|
71
71
|
exports.provideOrGenerateAscApiKeyAsync = provideOrGenerateAscApiKeyAsync;
|
|
72
72
|
async function generateAscApiKeyAsync(ctx, purpose) {
|
|
73
|
-
//console.log('debug');
|
|
74
73
|
await ctx.appStore.ensureAuthenticatedAsync();
|
|
75
74
|
const ascApiKey = await ctx.appStore.createAscApiKeyAsync({
|
|
76
75
|
nickname: getAscApiKeyName(purpose),
|
|
@@ -46,7 +46,7 @@ class ConfigureProvisioningProfile {
|
|
|
46
46
|
certP12: certificateP12,
|
|
47
47
|
certPassword: certificatePassword,
|
|
48
48
|
distCertSerialNumber: serialNumber,
|
|
49
|
-
teamId: authCtx.
|
|
49
|
+
teamId: authCtx.team.id,
|
|
50
50
|
});
|
|
51
51
|
const bundleIdTag = `(${app.bundleIdentifier})`;
|
|
52
52
|
const slugTag = `@${app.account.name}/${app.projectName}`;
|
|
@@ -45,7 +45,7 @@ class CreateProvisioningProfile {
|
|
|
45
45
|
certP12: this.distributionCertificate.certificateP12,
|
|
46
46
|
certPassword: this.distributionCertificate.certificatePassword,
|
|
47
47
|
distCertSerialNumber: this.distributionCertificate.serialNumber,
|
|
48
|
-
teamId: (_c = (_b = this.distributionCertificate.appleTeam) === null || _b === void 0 ? void 0 : _b.appleTeamIdentifier) !== null && _c !== void 0 ? _c : appleAuthCtx.
|
|
48
|
+
teamId: (_c = (_b = this.distributionCertificate.appleTeam) === null || _b === void 0 ? void 0 : _b.appleTeamIdentifier) !== null && _c !== void 0 ? _c : appleAuthCtx.team.id,
|
|
49
49
|
});
|
|
50
50
|
}
|
|
51
51
|
}
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { AscApiKey, AscApiKeyInfo, DistributionCertificate, DistributionCertificateStoreInfo, ProvisioningProfile, ProvisioningProfileStoreInfo, PushKey, PushKeyStoreInfo } from './Credentials.types';
|
|
2
|
-
import {
|
|
2
|
+
import { Options as AuthenticateOptions } from './authenticate';
|
|
3
|
+
import { AuthCtx, AuthenticationMode, UserAuthCtx } from './authenticateTypes';
|
|
3
4
|
import { AppLookupParams, IosCapabilitiesOptions } from './ensureAppExists';
|
|
4
5
|
import { ProfileClass } from './provisioningProfile';
|
|
5
6
|
export default class AppStoreApi {
|
|
6
7
|
authCtx?: AuthCtx;
|
|
8
|
+
defaultAuthenticationMode: AuthenticationMode;
|
|
9
|
+
constructor();
|
|
10
|
+
ensureUserAuthenticatedAsync(options?: AuthenticateOptions): Promise<UserAuthCtx>;
|
|
7
11
|
ensureAuthenticatedAsync(options?: AuthenticateOptions): Promise<AuthCtx>;
|
|
8
12
|
ensureBundleIdExistsAsync(app: AppLookupParams, options?: IosCapabilitiesOptions): Promise<void>;
|
|
9
13
|
listDistributionCertificatesAsync(): Promise<DistributionCertificateStoreInfo[]>;
|