eas-cli 0.59.0 → 1.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 +50 -47
- package/build/build/android/build.js +1 -1
- package/build/build/build.d.ts +1 -2
- package/build/build/build.js +6 -11
- package/build/build/runBuildAndSubmit.js +2 -0
- package/build/build/utils/printBuildInfo.js +2 -2
- package/build/build/utils/repository.js +4 -4
- package/build/commands/branch/create.js +1 -1
- package/build/commands/branch/delete.js +1 -1
- package/build/commands/branch/rename.js +2 -2
- package/build/commands/channel/create.js +1 -1
- package/build/commands/channel/delete.js +1 -1
- package/build/commands/channel/edit.js +3 -3
- package/build/commands/channel/rollout.js +3 -3
- package/build/commands/channel/view.js +1 -1
- package/build/commands/credentials.d.ts +3 -0
- package/build/commands/credentials.js +6 -1
- package/build/commands/metadata/pull.js +2 -2
- package/build/commands/project/init.js +3 -1
- package/build/commands/secret/list.js +1 -1
- package/build/commands/update/index.js +4 -4
- package/build/commands/update/list.js +1 -1
- package/build/credentials/android/actions/RemoveKeystore.js +1 -1
- package/build/credentials/errors.js +1 -1
- package/build/credentials/ios/actions/DistributionCertificateUtils.js +2 -2
- package/build/credentials/ios/actions/SetUpAdhocProvisioningProfile.js +1 -1
- package/build/credentials/ios/actions/SetUpInternalProvisioningProfile.js +2 -2
- package/build/credentials/ios/actions/SetUpProvisioningProfile.js +1 -1
- package/build/credentials/ios/actions/SetUpSubmissionCredentials.js +1 -1
- package/build/credentials/ios/appstore/contractMessages.js +1 -1
- package/build/credentials/ios/appstore/ensureAppExists.js +3 -3
- package/build/credentials/ios/appstore/pushKey.js +2 -2
- package/build/credentials/manager/SelectIosDistributionTypeGraphqlFromBuildProfile.js +1 -1
- package/build/credentials/manager/SelectPlatform.d.ts +2 -0
- package/build/credentials/manager/SelectPlatform.js +7 -12
- package/build/credentials/utils/promptForCredentials.js +1 -1
- package/build/devices/manager.js +1 -1
- package/build/graphql/client.js +1 -1
- package/build/graphql/generated.d.ts +35 -0
- package/build/metadata/config.d.ts +19 -0
- package/build/metadata/config.js +45 -1
- package/build/metadata/download.js +6 -5
- package/build/metadata/errors.js +2 -2
- package/build/metadata/upload.js +18 -21
- package/build/ora.js +1 -1
- package/build/project/metroConfig.js +1 -1
- package/build/project/projectUtils.d.ts +20 -2
- package/build/project/projectUtils.js +58 -32
- package/build/project/publish.js +8 -2
- package/build/submit/utils/errors.js +9 -9
- package/build/submit/utils/wait.js +1 -7
- package/build/update/utils.js +1 -1
- package/build/uploads.d.ts +1 -1
- package/build/uploads.js +64 -25
- package/build/vcs/clients/git.js +6 -2
- package/oclif.manifest.json +1 -1
- package/package.json +15 -14
|
@@ -48,7 +48,7 @@ async function startRolloutAsync({ channelName, branchName, percent, jsonFlag, p
|
|
|
48
48
|
name: branchName,
|
|
49
49
|
});
|
|
50
50
|
if (!branch) {
|
|
51
|
-
throw new Error(`Could not find a branch named "${branchName}".
|
|
51
|
+
throw new Error(`Could not find a branch named "${branchName}". Check which branches exist on this project with ${chalk_1.default.bold('eas branch:list')}.`);
|
|
52
52
|
}
|
|
53
53
|
const oldBranchId = currentBranchMapping.data[0].branchId;
|
|
54
54
|
if (branch.id === oldBranchId) {
|
|
@@ -114,7 +114,7 @@ async function endRolloutAsync({ channelName, branchName, jsonFlag, projectId, c
|
|
|
114
114
|
name: branchName,
|
|
115
115
|
});
|
|
116
116
|
if (!branch) {
|
|
117
|
-
throw new Error(`Could not find a branch named "${branchName}".
|
|
117
|
+
throw new Error(`Could not find a branch named "${branchName}". Check which branches exist on this project with ${chalk_1.default.bold('eas branch:list')}.`);
|
|
118
118
|
}
|
|
119
119
|
switch (branch.id) {
|
|
120
120
|
case newBranch.id:
|
|
@@ -176,7 +176,7 @@ class ChannelRollout extends EasCommand_1.default {
|
|
|
176
176
|
channelName: channelName,
|
|
177
177
|
});
|
|
178
178
|
if (!channel) {
|
|
179
|
-
throw new Error(`Could not find a channel named "${channelName}".
|
|
179
|
+
throw new Error(`Could not find a channel named "${channelName}". Check which channels exist on this project with ${chalk_1.default.bold('eas channel:list')}.`);
|
|
180
180
|
}
|
|
181
181
|
const { branchMapping: currentBranchMapping, isRollout } = (0, view_1.getBranchMapping)(channel.branchMapping);
|
|
182
182
|
if (currentBranchMapping.data.length === 0) {
|
|
@@ -119,7 +119,7 @@ class ChannelView extends EasCommand_1.default {
|
|
|
119
119
|
({ name: channelName } = await (0, prompts_1.promptAsync)({
|
|
120
120
|
type: 'text',
|
|
121
121
|
name: 'name',
|
|
122
|
-
message: '
|
|
122
|
+
message: 'Provide a channel name:',
|
|
123
123
|
validate: value => (value ? true : validationMessage),
|
|
124
124
|
}));
|
|
125
125
|
}
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
|
+
const core_1 = require("@oclif/core");
|
|
4
5
|
const EasCommand_1 = tslib_1.__importDefault(require("../commandUtils/EasCommand"));
|
|
5
6
|
const SelectPlatform_1 = require("../credentials/manager/SelectPlatform");
|
|
6
7
|
class Credentials extends EasCommand_1.default {
|
|
7
8
|
async runAsync() {
|
|
8
|
-
await
|
|
9
|
+
const { flags } = await this.parse(Credentials);
|
|
10
|
+
await new SelectPlatform_1.SelectPlatform(flags.platform).runAsync();
|
|
9
11
|
}
|
|
10
12
|
}
|
|
11
13
|
exports.default = Credentials;
|
|
12
14
|
Credentials.description = 'manage credentials';
|
|
15
|
+
Credentials.flags = {
|
|
16
|
+
platform: core_1.Flags.enum({ char: 'p', options: ['android', 'ios'] }),
|
|
17
|
+
};
|
|
@@ -38,11 +38,11 @@ class MetadataPull extends EasCommand_1.default {
|
|
|
38
38
|
const filePath = await (0, download_1.downloadMetadataAsync)(metadataCtx);
|
|
39
39
|
const relativePath = path_1.default.relative(process.cwd(), filePath);
|
|
40
40
|
log_1.default.addNewLineIfNone();
|
|
41
|
-
log_1.default.log(`🎉 Your store
|
|
41
|
+
log_1.default.log(`🎉 Your store config is ready.
|
|
42
42
|
|
|
43
43
|
- Update the ${chalk_1.default.bold(relativePath)} file to prepare the app information.
|
|
44
44
|
- Run ${chalk_1.default.bold('eas submit')} or manually upload a new app version to the app stores.
|
|
45
|
-
- Once the app is uploaded, run ${chalk_1.default.bold('eas metadata:push')} to sync the store
|
|
45
|
+
- Once the app is uploaded, run ${chalk_1.default.bold('eas metadata:push')} to sync the store config.
|
|
46
46
|
- ${(0, log_1.learnMore)('https://docs.expo.dev/eas-metadata/introduction/')}`);
|
|
47
47
|
}
|
|
48
48
|
catch (error) {
|
|
@@ -15,7 +15,9 @@ class ProjectInit extends EasCommand_1.default {
|
|
|
15
15
|
log_1.default.error(`app.json is already linked to project with ID: ${chalk_1.default.bold((_d = (_c = exp.extra) === null || _c === void 0 ? void 0 : _c.eas) === null || _d === void 0 ? void 0 : _d.projectId)}`);
|
|
16
16
|
return;
|
|
17
17
|
}
|
|
18
|
-
await (0, projectUtils_1.
|
|
18
|
+
const projectId = await (0, projectUtils_1.fetchProjectIdFromServerAsync)(exp);
|
|
19
|
+
await (0, projectUtils_1.saveProjectIdToAppConfigAsync)(projectDir, projectId);
|
|
20
|
+
log_1.default.withTick(`Linked app.json to project with ID ${chalk_1.default.bold(projectId)}`);
|
|
19
21
|
}
|
|
20
22
|
}
|
|
21
23
|
exports.default = ProjectInit;
|
|
@@ -16,7 +16,7 @@ class EnvironmentSecretList extends EasCommand_1.default {
|
|
|
16
16
|
const projectId = await (0, projectUtils_1.getProjectIdAsync)(exp);
|
|
17
17
|
const projectAccountName = await (0, projectUtils_1.getProjectAccountNameAsync)(exp);
|
|
18
18
|
if (!projectDir) {
|
|
19
|
-
throw new Error("
|
|
19
|
+
throw new Error("Run this command inside your project's directory");
|
|
20
20
|
}
|
|
21
21
|
const secrets = await EnvironmentSecretsQuery_1.EnvironmentSecretsQuery.allAsync(projectAccountName, projectId);
|
|
22
22
|
const table = new cli_table3_1.default({
|
|
@@ -153,7 +153,7 @@ class UpdatePublish extends EasCommand_1.default {
|
|
|
153
153
|
({ name: branchName } = await (0, prompts_1.promptAsync)({
|
|
154
154
|
type: 'text',
|
|
155
155
|
name: 'name',
|
|
156
|
-
message: 'No branches found.
|
|
156
|
+
message: 'No branches found. Provide a branch name:',
|
|
157
157
|
initial: (await (0, vcs_1.getVcsClient)().getBranchNameAsync()) ||
|
|
158
158
|
`branch-${Math.random().toString(36).substr(2, 4)}`,
|
|
159
159
|
validate: value => (value ? true : validationMessage),
|
|
@@ -229,7 +229,7 @@ class UpdatePublish extends EasCommand_1.default {
|
|
|
229
229
|
({ publishMessage: message } = await (0, prompts_1.promptAsync)({
|
|
230
230
|
type: 'text',
|
|
231
231
|
name: 'publishMessage',
|
|
232
|
-
message: `
|
|
232
|
+
message: `Provide an update message.`,
|
|
233
233
|
initial: `Republish "${oldMessage}" - group: ${group}`,
|
|
234
234
|
validate: (value) => (value ? true : validationMessage),
|
|
235
235
|
}));
|
|
@@ -250,7 +250,7 @@ class UpdatePublish extends EasCommand_1.default {
|
|
|
250
250
|
({ publishMessage: message } = await (0, prompts_1.promptAsync)({
|
|
251
251
|
type: 'text',
|
|
252
252
|
name: 'publishMessage',
|
|
253
|
-
message: `
|
|
253
|
+
message: `Provide an update message.`,
|
|
254
254
|
initial: (_c = (await (0, vcs_1.getVcsClient)().getLastCommitMessageAsync())) === null || _c === void 0 ? void 0 : _c.trim(),
|
|
255
255
|
validate: (value) => (value ? true : validationMessage),
|
|
256
256
|
}));
|
|
@@ -529,7 +529,7 @@ async function checkEASUpdateURLIsSetAsync(exp) {
|
|
|
529
529
|
const projectId = await (0, projectUtils_1.getProjectIdAsync)(exp);
|
|
530
530
|
const expectedURL = (0, api_1.getEASUpdateURL)(projectId);
|
|
531
531
|
if (configuredURL !== expectedURL) {
|
|
532
|
-
throw new Error(`The update URL is incorrectly configured for EAS Update.
|
|
532
|
+
throw new Error(`The update URL is incorrectly configured for EAS Update. Set updates.url to ${expectedURL} in your ${chalk_1.default.bold('app.json')}.`);
|
|
533
533
|
}
|
|
534
534
|
}
|
|
535
535
|
const truncatePublishUpdateMessage = (originalMessage) => {
|
|
@@ -47,7 +47,7 @@ class BranchView extends EasCommand_1.default {
|
|
|
47
47
|
({ name: branchInteractive } = await (0, prompts_1.promptAsync)({
|
|
48
48
|
type: 'text',
|
|
49
49
|
name: 'name',
|
|
50
|
-
message: '
|
|
50
|
+
message: 'Provide the name of the branch whose updates you wish to view:',
|
|
51
51
|
initial: (_a = (await (0, vcs_1.getVcsClient)().getBranchNameAsync())) !== null && _a !== void 0 ? _a : undefined,
|
|
52
52
|
validate: (value) => (value ? true : validationMessage),
|
|
53
53
|
}));
|
|
@@ -35,7 +35,7 @@ class RemoveKeystore {
|
|
|
35
35
|
log_1.default.newLine();
|
|
36
36
|
log_1.default.warn(`Clearing your Android build credentials from our build servers is a ${chalk_1.default.bold('PERMANENT and IRREVERSIBLE action.')}`);
|
|
37
37
|
log_1.default.warn(chalk_1.default.bold('Android Keystore must be identical to the one previously used to submit your app to the Google Play Store.'));
|
|
38
|
-
log_1.default.warn('
|
|
38
|
+
log_1.default.warn('Read https://docs.expo.dev/distribution/building-standalone-apps/#if-you-choose-to-build-for-android for more info before proceeding.');
|
|
39
39
|
log_1.default.newLine();
|
|
40
40
|
log_1.default.warn(chalk_1.default.bold('Your Keystore will be backed up to your current directory if you continue.'));
|
|
41
41
|
log_1.default.newLine();
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.UnsupportedCredentialsChoiceError = exports.MissingCredentialsError = exports.MissingCredentialsNonInteractiveError = void 0;
|
|
4
4
|
class MissingCredentialsNonInteractiveError extends Error {
|
|
5
5
|
constructor(message) {
|
|
6
|
-
super(message !== null && message !== void 0 ? message : 'Credentials are not set up.
|
|
6
|
+
super(message !== null && message !== void 0 ? message : 'Credentials are not set up. Run this command again in interactive mode.');
|
|
7
7
|
}
|
|
8
8
|
}
|
|
9
9
|
exports.MissingCredentialsNonInteractiveError = MissingCredentialsNonInteractiveError;
|
|
@@ -96,8 +96,8 @@ async function selectValidDistributionCertificateAsync(ctx, appLookupParams) {
|
|
|
96
96
|
exports.selectValidDistributionCertificateAsync = selectValidDistributionCertificateAsync;
|
|
97
97
|
const APPLE_DIST_CERTS_TOO_MANY_GENERATED_ERROR = `
|
|
98
98
|
You can have only ${chalk_1.default.underline('three')} Apple Distribution Certificates generated on your Apple Developer account.
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
Revoke the old ones or reuse existing from your other apps.
|
|
100
|
+
Remember that Apple Distribution Certificates are not application specific!
|
|
101
101
|
`;
|
|
102
102
|
async function provideOrGenerateDistributionCertificateAsync(ctx) {
|
|
103
103
|
if (!ctx.nonInteractive) {
|
|
@@ -34,7 +34,7 @@ class SetUpAdhocProvisioningProfile {
|
|
|
34
34
|
return (0, nullthrows_1.default)(await (0, BuildCredentialsUtils_1.getBuildCredentialsAsync)(ctx, this.app, generated_1.IosDistributionType.AdHoc));
|
|
35
35
|
}
|
|
36
36
|
else {
|
|
37
|
-
throw new errors_1.MissingCredentialsNonInteractiveError('Provisioning profile is not configured correctly.
|
|
37
|
+
throw new errors_1.MissingCredentialsNonInteractiveError('Provisioning profile is not configured correctly. Run this command again in interactive mode.');
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
const currentBuildCredentials = await (0, BuildCredentialsUtils_1.getBuildCredentialsAsync)(ctx, this.app, generated_1.IosDistributionType.AdHoc);
|
|
@@ -59,7 +59,7 @@ class SetUpInternalProvisioningProfile {
|
|
|
59
59
|
}
|
|
60
60
|
else {
|
|
61
61
|
if (adhocBuildCredentialsExist && enterpriseBuildCredentialsExist) {
|
|
62
|
-
throw new Error(`You're in non-interactive mode. You have set up both adhoc and universal distribution credentials.
|
|
62
|
+
throw new Error(`You're in non-interactive mode. You have set up both adhoc and universal distribution credentials. Set the 'enterpriseProvisioning' property (to 'adhoc' or 'universal') in eas.json to choose the credentials to use.`);
|
|
63
63
|
}
|
|
64
64
|
else if (adhocBuildCredentialsExist) {
|
|
65
65
|
return await this.setupAdhocProvisioningProfileAsync(ctx);
|
|
@@ -68,7 +68,7 @@ class SetUpInternalProvisioningProfile {
|
|
|
68
68
|
return await this.setupUniversalProvisioningProfileAsync(ctx);
|
|
69
69
|
}
|
|
70
70
|
else {
|
|
71
|
-
throw new Error(`You're in non-interactive mode. EAS CLI couldn't find any credentials suitable for internal distribution.
|
|
71
|
+
throw new Error(`You're in non-interactive mode. EAS CLI couldn't find any credentials suitable for internal distribution. Run this command again in interactive mode.`);
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
}
|
|
@@ -48,7 +48,7 @@ class SetUpProvisioningProfile {
|
|
|
48
48
|
return (0, nullthrows_1.default)(await (0, BuildCredentialsUtils_1.getBuildCredentialsAsync)(ctx, this.app, this.distributionType));
|
|
49
49
|
}
|
|
50
50
|
if (ctx.nonInteractive) {
|
|
51
|
-
throw new errors_1.MissingCredentialsNonInteractiveError('Provisioning profile is not configured correctly.
|
|
51
|
+
throw new errors_1.MissingCredentialsNonInteractiveError('Provisioning profile is not configured correctly. Run this command again in interactive mode.');
|
|
52
52
|
}
|
|
53
53
|
const currentProfile = await (0, BuildCredentialsUtils_1.getProvisioningProfileAsync)(ctx, this.app, this.distributionType);
|
|
54
54
|
if (!currentProfile) {
|
|
@@ -38,7 +38,7 @@ class SetUpSubmissionCredentials {
|
|
|
38
38
|
}
|
|
39
39
|
async promptForAppSpecificPasswordAsync() {
|
|
40
40
|
log_1.default.addNewLineIfNone();
|
|
41
|
-
log_1.default.log(`
|
|
41
|
+
log_1.default.log(`Enter your Apple app-specific password.`);
|
|
42
42
|
log_1.default.log((0, log_1.learnMore)('https://expo.fyi/apple-app-specific-password'));
|
|
43
43
|
log_1.default.warn((0, wrap_ansi_1.default)(`This option will be deprecated soon. You will still be able to provide your password with the ${chalk_1.default.bold('EXPO_APPLE_APP_SPECIFIC_PASSWORD')} environment variable.`, process.stdout.columns || 80));
|
|
44
44
|
const { appSpecificPassword } = await (0, prompts_1.promptAsync)({
|
|
@@ -59,7 +59,7 @@ async function getRequiredContractMessagesAsync(context) {
|
|
|
59
59
|
// There is a small chance that this could result in a false positive if the messages are extraneous, so we'll also
|
|
60
60
|
// prompt the user to open an issue so we can address the new contract state if it ever appears.
|
|
61
61
|
// TODO: Maybe a silent analytic would be better
|
|
62
|
-
log_1.default.error(`\nUnexpected Apple developer contract status "${status}".
|
|
62
|
+
log_1.default.error(`\nUnexpected Apple developer contract status "${status}". Open an issue on https://github.com/expo/eas-cli`);
|
|
63
63
|
log_1.default.newLine();
|
|
64
64
|
return { messages: (_b = (await getContractMessagesAsync(context))) !== null && _b !== void 0 ? _b : [], isFatal: false };
|
|
65
65
|
}
|
|
@@ -36,7 +36,7 @@ async function ensureBundleIdExistsWithNameAsync(authCtx, { name, bundleIdentifi
|
|
|
36
36
|
}
|
|
37
37
|
catch (err) {
|
|
38
38
|
if (err.message.match(/An App ID with Identifier '(.*)' is not available/)) {
|
|
39
|
-
spinner.fail(`The bundle identifier ${chalk_1.default.bold(bundleIdentifier)} is not available to team "${authCtx.team.name}" (${authCtx.team.id}),
|
|
39
|
+
spinner.fail(`The bundle identifier ${chalk_1.default.bold(bundleIdentifier)} is not available to team "${authCtx.team.name}" (${authCtx.team.id}), change it in your app config and try again.`);
|
|
40
40
|
}
|
|
41
41
|
else {
|
|
42
42
|
spinner.fail(`Failed to register bundle identifier ${chalk_1.default.dim(bundleIdentifier)}`);
|
|
@@ -123,11 +123,11 @@ async function ensureAppExistsAsync(userAuthCtx, { name, language, companyName,
|
|
|
123
123
|
}
|
|
124
124
|
catch (error) {
|
|
125
125
|
if (error.message.match(/An App ID with Identifier '(.*)' is not available/)) {
|
|
126
|
-
throw new Error(`\nThe bundle identifier "${bundleIdentifier}" is not available to provider "${(_a = userAuthCtx.authState) === null || _a === void 0 ? void 0 : _a.session.provider.name}.
|
|
126
|
+
throw new Error(`\nThe bundle identifier "${bundleIdentifier}" is not available to provider "${(_a = userAuthCtx.authState) === null || _a === void 0 ? void 0 : _a.session.provider.name}. Change it in your app config and try again.\n`);
|
|
127
127
|
}
|
|
128
128
|
spinner.fail(`Failed to create App Store app ${chalk_1.default.dim(name)}`);
|
|
129
129
|
error.message +=
|
|
130
|
-
'\
|
|
130
|
+
'\nVisit https://appstoreconnect.apple.com and resolve any warnings, then try again.';
|
|
131
131
|
throw error;
|
|
132
132
|
}
|
|
133
133
|
}
|
|
@@ -11,8 +11,8 @@ const authenticate_1 = require("./authenticate");
|
|
|
11
11
|
const { MaxKeysCreatedError } = apple_utils_1.Keys;
|
|
12
12
|
exports.APPLE_KEYS_TOO_MANY_GENERATED_ERROR = `
|
|
13
13
|
You can have only ${chalk_1.default.underline('two')} Apple Keys generated on your Apple Developer account.
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
Revoke the old ones or reuse existing from your other apps.
|
|
15
|
+
Remember that Apple Keys are not application specific!
|
|
16
16
|
`;
|
|
17
17
|
/**
|
|
18
18
|
* List all existing push keys on Apple servers.
|
|
@@ -39,7 +39,7 @@ class SelectIosDistributionTypeGraphqlFromBuildProfile {
|
|
|
39
39
|
return generated_1.IosDistributionType.AdHoc;
|
|
40
40
|
}
|
|
41
41
|
if (ctx.nonInteractive) {
|
|
42
|
-
throw new Error('Unable to determine type of internal distribution.
|
|
42
|
+
throw new Error('Unable to determine type of internal distribution. Run this command in interactive mode.');
|
|
43
43
|
}
|
|
44
44
|
// ask the user as a last resort
|
|
45
45
|
const { iosDistributionTypeGraphql } = await (0, prompts_1.promptAsync)({
|
|
@@ -1,24 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SelectPlatform = void 0;
|
|
4
|
-
const
|
|
4
|
+
const platform_1 = require("../../platform");
|
|
5
5
|
const ManageAndroid_1 = require("./ManageAndroid");
|
|
6
6
|
const ManageIos_1 = require("./ManageIos");
|
|
7
7
|
class SelectPlatform {
|
|
8
|
+
constructor(flagPlatform) {
|
|
9
|
+
this.flagPlatform = flagPlatform;
|
|
10
|
+
}
|
|
8
11
|
async runAsync() {
|
|
9
|
-
const
|
|
10
|
-
type: 'select',
|
|
11
|
-
name: 'platform',
|
|
12
|
-
message: 'Select platform',
|
|
13
|
-
choices: [
|
|
14
|
-
{ value: 'android', title: 'Android' },
|
|
15
|
-
{ value: 'ios', title: 'iOS' },
|
|
16
|
-
],
|
|
17
|
-
});
|
|
12
|
+
const platform = await (0, platform_1.selectPlatformAsync)(this.flagPlatform);
|
|
18
13
|
if (platform === 'ios') {
|
|
19
|
-
return await new ManageIos_1.ManageIos(new SelectPlatform(), process.cwd()).runAsync();
|
|
14
|
+
return await new ManageIos_1.ManageIos(new SelectPlatform(platform), process.cwd()).runAsync();
|
|
20
15
|
}
|
|
21
|
-
return await new ManageAndroid_1.ManageAndroid(new SelectPlatform(), process.cwd()).runAsync();
|
|
16
|
+
return await new ManageAndroid_1.ManageAndroid(new SelectPlatform(platform), process.cwd()).runAsync();
|
|
22
17
|
}
|
|
23
18
|
}
|
|
24
19
|
exports.SelectPlatform = SelectPlatform;
|
|
@@ -14,7 +14,7 @@ const EXPERT_PROMPT = () => {
|
|
|
14
14
|
}
|
|
15
15
|
log_1.default.warn(`
|
|
16
16
|
In this mode, we won't be able to make sure that your credentials are valid.
|
|
17
|
-
|
|
17
|
+
Double check that you're uploading valid files for your app otherwise you may encounter strange errors!
|
|
18
18
|
When building for IOS make sure you've created your App ID on the Apple Developer Portal, that your App ID
|
|
19
19
|
is in app.json as \`bundleIdentifier\`, and that the provisioning profile you
|
|
20
20
|
upload matches that Team ID and App ID.
|
package/build/devices/manager.js
CHANGED
|
@@ -17,7 +17,7 @@ Internal distribution means that you won't need upload your app archive to App S
|
|
|
17
17
|
Your app archive (.ipa) will be installable on your equipment as long as you sign your application with an adhoc provisiong profile.
|
|
18
18
|
The provisioning profile needs to contain the UDIDs (unique identifiers) of your iPhones and iPads.
|
|
19
19
|
|
|
20
|
-
First of all,
|
|
20
|
+
First of all, choose the Expo account under which you want to register your devices.
|
|
21
21
|
Later, authenticate with Apple and choose your desired Apple Team (if your Apple ID has access to multiple teams).`;
|
|
22
22
|
class DeviceManager {
|
|
23
23
|
constructor(ctx) {
|
package/build/graphql/client.js
CHANGED
|
@@ -47,7 +47,7 @@ async function withErrorHandlingAsync(promise) {
|
|
|
47
47
|
const { data, error } = await promise;
|
|
48
48
|
if (error) {
|
|
49
49
|
if (error.graphQLErrors.some(e => { var _a; return (_a = e === null || e === void 0 ? void 0 : e.extensions) === null || _a === void 0 ? void 0 : _a.isTransient; })) {
|
|
50
|
-
log_1.default.error(`We've encountered a transient error
|
|
50
|
+
log_1.default.error(`We've encountered a transient error. Try again shortly.`);
|
|
51
51
|
}
|
|
52
52
|
throw error;
|
|
53
53
|
}
|
|
@@ -102,6 +102,8 @@ export declare type Account = {
|
|
|
102
102
|
createdAt: Scalars['DateTime'];
|
|
103
103
|
/** Environment secrets for an account */
|
|
104
104
|
environmentSecrets: Array<EnvironmentSecret>;
|
|
105
|
+
/** GitHub App installations for an account */
|
|
106
|
+
githubAppInstallations: Array<GitHubAppInstallation>;
|
|
105
107
|
/** Android credentials for account */
|
|
106
108
|
googleServiceAccountKeys: Array<GoogleServiceAccountKey>;
|
|
107
109
|
id: Scalars['ID'];
|
|
@@ -1815,6 +1817,10 @@ export declare type CreateEnvironmentSecretInput = {
|
|
|
1815
1817
|
name: Scalars['String'];
|
|
1816
1818
|
value: Scalars['String'];
|
|
1817
1819
|
};
|
|
1820
|
+
export declare type CreateGitHubAppInstallationInput = {
|
|
1821
|
+
accountId: Scalars['ID'];
|
|
1822
|
+
installationIdentifier: Scalars['Int'];
|
|
1823
|
+
};
|
|
1818
1824
|
export declare type CreateIosSubmissionInput = {
|
|
1819
1825
|
appId: Scalars['ID'];
|
|
1820
1826
|
archiveUrl?: InputMaybe<Scalars['String']>;
|
|
@@ -2011,6 +2017,31 @@ export declare type GetSignedAssetUploadSpecificationsResult = {
|
|
|
2011
2017
|
__typename?: 'GetSignedAssetUploadSpecificationsResult';
|
|
2012
2018
|
specifications: Array<Scalars['String']>;
|
|
2013
2019
|
};
|
|
2020
|
+
export declare type GitHubAppInstallation = {
|
|
2021
|
+
__typename?: 'GitHubAppInstallation';
|
|
2022
|
+
account: Account;
|
|
2023
|
+
actor?: Maybe<Actor>;
|
|
2024
|
+
id: Scalars['ID'];
|
|
2025
|
+
installationIdentifier: Scalars['Int'];
|
|
2026
|
+
};
|
|
2027
|
+
export declare type GitHubAppInstallationMutation = {
|
|
2028
|
+
__typename?: 'GitHubAppInstallationMutation';
|
|
2029
|
+
/** Create a GitHub App installation for an Account */
|
|
2030
|
+
createGitHubAppInstallationForAccount: GitHubAppInstallation;
|
|
2031
|
+
/** Delete a GitHub App installation by ID */
|
|
2032
|
+
deleteGitHubAppInstallation: GitHubAppInstallation;
|
|
2033
|
+
};
|
|
2034
|
+
export declare type GitHubAppInstallationMutationCreateGitHubAppInstallationForAccountArgs = {
|
|
2035
|
+
githubAppInstallationData: CreateGitHubAppInstallationInput;
|
|
2036
|
+
};
|
|
2037
|
+
export declare type GitHubAppInstallationMutationDeleteGitHubAppInstallationArgs = {
|
|
2038
|
+
githubAppInstallationId: Scalars['ID'];
|
|
2039
|
+
};
|
|
2040
|
+
export declare type GitHubAppQuery = {
|
|
2041
|
+
__typename?: 'GitHubAppQuery';
|
|
2042
|
+
appIdentifier: Scalars['String'];
|
|
2043
|
+
clientIdentifier: Scalars['String'];
|
|
2044
|
+
};
|
|
2014
2045
|
export declare type GoogleServiceAccountKey = {
|
|
2015
2046
|
__typename?: 'GoogleServiceAccountKey';
|
|
2016
2047
|
account: Account;
|
|
@@ -2611,6 +2642,8 @@ export declare type RootMutation = {
|
|
|
2611
2642
|
emailSubscription: EmailSubscriptionMutation;
|
|
2612
2643
|
/** Mutations that create and delete EnvironmentSecrets */
|
|
2613
2644
|
environmentSecret: EnvironmentSecretMutation;
|
|
2645
|
+
/** Mutations for GitHub App installations */
|
|
2646
|
+
githubAppInstallation: GitHubAppInstallationMutation;
|
|
2614
2647
|
/** Mutations that modify a Google Service Account Key */
|
|
2615
2648
|
googleServiceAccountKey: GoogleServiceAccountKeyMutation;
|
|
2616
2649
|
/** Mutations that modify the build credentials for an iOS app */
|
|
@@ -2648,6 +2681,8 @@ export declare type RootMutationBuildJobArgs = {
|
|
|
2648
2681
|
};
|
|
2649
2682
|
export declare type RootQuery = {
|
|
2650
2683
|
__typename?: 'RootQuery';
|
|
2684
|
+
/** Top-level query object for querying GitHub App information and resources it has access to. */
|
|
2685
|
+
GitHubApp: GitHubAppQuery;
|
|
2651
2686
|
/**
|
|
2652
2687
|
* This is a placeholder field
|
|
2653
2688
|
* @deprecated Not used.
|
|
@@ -8,6 +8,25 @@ export interface MetadataConfig {
|
|
|
8
8
|
/** All App Store related configuration */
|
|
9
9
|
apple?: AppleMetadata;
|
|
10
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Get the static configuration file path, based on the metadata context.
|
|
13
|
+
* This uses any custom name provided, but swaps out the extension for `.json`.
|
|
14
|
+
*/
|
|
15
|
+
export declare function getStaticConfigFilePath({ projectDir, metadataPath, }: {
|
|
16
|
+
projectDir: string;
|
|
17
|
+
metadataPath: string;
|
|
18
|
+
}): string;
|
|
19
|
+
/**
|
|
20
|
+
* Load the store configuration from a metadata context.
|
|
21
|
+
* This can load `.json` and `.js` config files, using `require`.
|
|
22
|
+
* It throws MetadataValidationErrors when the file doesn't exist, or contains errors.
|
|
23
|
+
* The user is prompted to try anyway when errors are found.
|
|
24
|
+
*/
|
|
25
|
+
export declare function loadConfigAsync({ projectDir, metadataPath, skipValidation, }: {
|
|
26
|
+
projectDir: string;
|
|
27
|
+
metadataPath: string;
|
|
28
|
+
skipValidation?: boolean;
|
|
29
|
+
}): Promise<MetadataConfig>;
|
|
11
30
|
/**
|
|
12
31
|
* Run the JSON Schema validation to normalize defaults and flag early config errors.
|
|
13
32
|
* This includes validating the known store limitations for every configurable property.
|
package/build/metadata/config.js
CHANGED
|
@@ -1,11 +1,55 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createAppleWriter = exports.createAppleReader = exports.validateConfig = void 0;
|
|
3
|
+
exports.createAppleWriter = exports.createAppleReader = exports.validateConfig = exports.loadConfigAsync = exports.getStaticConfigFilePath = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const ajv_1 = tslib_1.__importDefault(require("ajv"));
|
|
6
6
|
const assert_1 = tslib_1.__importDefault(require("assert"));
|
|
7
|
+
const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
|
|
8
|
+
const path_1 = tslib_1.__importDefault(require("path"));
|
|
7
9
|
const reader_1 = require("./apple/config/reader");
|
|
8
10
|
const writer_1 = require("./apple/config/writer");
|
|
11
|
+
const errors_1 = require("./errors");
|
|
12
|
+
/**
|
|
13
|
+
* Resolve the dynamic config from the user.
|
|
14
|
+
* It supports methods, async methods, or objects (json).
|
|
15
|
+
*/
|
|
16
|
+
async function resolveDynamicConfigAsync(configFile) {
|
|
17
|
+
const userConfigOrFunction = await Promise.resolve().then(() => tslib_1.__importStar(require(configFile))).then(file => { var _a; return (_a = file.default) !== null && _a !== void 0 ? _a : file; });
|
|
18
|
+
return typeof userConfigOrFunction === 'function'
|
|
19
|
+
? await userConfigOrFunction()
|
|
20
|
+
: userConfigOrFunction;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Get the static configuration file path, based on the metadata context.
|
|
24
|
+
* This uses any custom name provided, but swaps out the extension for `.json`.
|
|
25
|
+
*/
|
|
26
|
+
function getStaticConfigFilePath({ projectDir, metadataPath, }) {
|
|
27
|
+
const configFile = path_1.default.join(projectDir, metadataPath);
|
|
28
|
+
const configExtension = path_1.default.extname(configFile);
|
|
29
|
+
return path_1.default.join(projectDir, `${path_1.default.basename(configFile, configExtension)}.json`);
|
|
30
|
+
}
|
|
31
|
+
exports.getStaticConfigFilePath = getStaticConfigFilePath;
|
|
32
|
+
/**
|
|
33
|
+
* Load the store configuration from a metadata context.
|
|
34
|
+
* This can load `.json` and `.js` config files, using `require`.
|
|
35
|
+
* It throws MetadataValidationErrors when the file doesn't exist, or contains errors.
|
|
36
|
+
* The user is prompted to try anyway when errors are found.
|
|
37
|
+
*/
|
|
38
|
+
async function loadConfigAsync({ projectDir, metadataPath, skipValidation = false, }) {
|
|
39
|
+
const configFile = path_1.default.join(projectDir, metadataPath);
|
|
40
|
+
if (!(await fs_extra_1.default.pathExists(configFile))) {
|
|
41
|
+
throw new errors_1.MetadataValidationError(`Metadata store config file not found: "${configFile}"`);
|
|
42
|
+
}
|
|
43
|
+
const configData = await resolveDynamicConfigAsync(configFile);
|
|
44
|
+
if (!skipValidation) {
|
|
45
|
+
const { valid, errors: validationErrors } = validateConfig(configData);
|
|
46
|
+
if (!valid) {
|
|
47
|
+
throw new errors_1.MetadataValidationError(`Metadata store config errors found`, validationErrors);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return configData;
|
|
51
|
+
}
|
|
52
|
+
exports.loadConfigAsync = loadConfigAsync;
|
|
9
53
|
/**
|
|
10
54
|
* Run the JSON Schema validation to normalize defaults and flag early config errors.
|
|
11
55
|
* This includes validating the known store limitations for every configurable property.
|
|
@@ -17,20 +17,21 @@ const telemetry_1 = require("./utils/telemetry");
|
|
|
17
17
|
* Note, only App Store is supported at this time.
|
|
18
18
|
*/
|
|
19
19
|
async function downloadMetadataAsync(metadataCtx) {
|
|
20
|
-
const filePath =
|
|
20
|
+
const filePath = (0, config_1.getStaticConfigFilePath)(metadataCtx);
|
|
21
21
|
const fileExists = await fs_extra_1.default.pathExists(filePath);
|
|
22
22
|
if (fileExists) {
|
|
23
|
+
const filePathRelative = path_1.default.relative(metadataCtx.projectDir, filePath);
|
|
23
24
|
const overwrite = await (0, prompts_1.confirmAsync)({
|
|
24
|
-
message: `Do you want to overwrite the existing
|
|
25
|
+
message: `Do you want to overwrite the existing "${filePathRelative}"?`,
|
|
25
26
|
});
|
|
26
27
|
if (!overwrite) {
|
|
27
|
-
throw new errors_1.MetadataValidationError(`Store
|
|
28
|
+
throw new errors_1.MetadataValidationError(`Store config already exists at "${filePath}"`);
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
31
|
const { app, auth } = await (0, context_1.ensureMetadataAppStoreAuthenticatedAsync)(metadataCtx);
|
|
31
32
|
const { unsubscribeTelemetry, executionId } = (0, telemetry_1.subscribeTelemetry)(events_1.MetadataEvent.APPLE_METADATA_DOWNLOAD, { app, auth });
|
|
32
33
|
log_1.default.addNewLineIfNone();
|
|
33
|
-
log_1.default.log('Downloading App Store
|
|
34
|
+
log_1.default.log('Downloading App Store config...');
|
|
34
35
|
const errors = [];
|
|
35
36
|
const config = (0, config_1.createAppleWriter)();
|
|
36
37
|
const tasks = (0, tasks_1.createAppleTasks)(metadataCtx);
|
|
@@ -52,7 +53,7 @@ async function downloadMetadataAsync(metadataCtx) {
|
|
|
52
53
|
}
|
|
53
54
|
}
|
|
54
55
|
try {
|
|
55
|
-
await fs_extra_1.default.
|
|
56
|
+
await fs_extra_1.default.writeJSON(filePath, config.toSchema(), { spaces: 2 });
|
|
56
57
|
}
|
|
57
58
|
finally {
|
|
58
59
|
unsubscribeTelemetry();
|
package/build/metadata/errors.js
CHANGED
|
@@ -75,8 +75,8 @@ function handleMetadataError(error) {
|
|
|
75
75
|
log_1.default.error(error.errors.map(err => err.message).join('\n\n'));
|
|
76
76
|
}
|
|
77
77
|
log_1.default.newLine();
|
|
78
|
-
log_1.default.log('
|
|
79
|
-
log_1.default.log('If this issue persists,
|
|
78
|
+
log_1.default.log('Check the logs for any configuration issues.');
|
|
79
|
+
log_1.default.log('If this issue persists, open a new issue at:');
|
|
80
80
|
// TODO: add execution ID to the issue template link
|
|
81
81
|
log_1.default.log((0, log_1.link)('https://github.com/expo/eas-cli'));
|
|
82
82
|
return;
|
package/build/metadata/upload.js
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.uploadMetadataAsync = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
-
const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
|
|
6
|
-
const path_1 = tslib_1.__importDefault(require("path"));
|
|
7
5
|
const events_1 = require("../analytics/events");
|
|
8
6
|
const log_1 = tslib_1.__importDefault(require("../log"));
|
|
9
7
|
const prompts_1 = require("../prompts");
|
|
@@ -18,30 +16,13 @@ const telemetry_1 = require("./utils/telemetry");
|
|
|
18
16
|
*/
|
|
19
17
|
async function uploadMetadataAsync(metadataCtx) {
|
|
20
18
|
var _a;
|
|
21
|
-
const
|
|
22
|
-
if (!(await fs_extra_1.default.pathExists(filePath))) {
|
|
23
|
-
throw new errors_1.MetadataValidationError(`Store configuration file not found "${filePath}"`);
|
|
24
|
-
}
|
|
25
|
-
const fileData = await fs_extra_1.default.readJson(filePath);
|
|
26
|
-
const { valid, errors: validationErrors } = (0, config_1.validateConfig)(fileData);
|
|
27
|
-
if (!valid) {
|
|
28
|
-
const error = new errors_1.MetadataValidationError(`Store configuration errors found`, validationErrors);
|
|
29
|
-
(0, errors_1.logMetadataValidationError)(error);
|
|
30
|
-
log_1.default.newLine();
|
|
31
|
-
log_1.default.warn('Without further updates, the current store configuration may fail to be synchronized with the App Store or pass App Store review.');
|
|
32
|
-
const attempt = await (0, prompts_1.confirmAsync)({
|
|
33
|
-
message: 'Do you still want to push the store configuration?',
|
|
34
|
-
});
|
|
35
|
-
if (!attempt) {
|
|
36
|
-
throw error;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
19
|
+
const storeConfig = await loadConfigWithValidationPromptAsync(metadataCtx);
|
|
39
20
|
const { app, auth } = await (0, context_1.ensureMetadataAppStoreAuthenticatedAsync)(metadataCtx);
|
|
40
21
|
const { unsubscribeTelemetry, executionId } = (0, telemetry_1.subscribeTelemetry)(events_1.MetadataEvent.APPLE_METADATA_UPLOAD, { app, auth });
|
|
41
22
|
log_1.default.addNewLineIfNone();
|
|
42
23
|
log_1.default.log('Uploading App Store configuration...');
|
|
43
24
|
const errors = [];
|
|
44
|
-
const config = (0, config_1.createAppleReader)(
|
|
25
|
+
const config = (0, config_1.createAppleReader)(storeConfig);
|
|
45
26
|
const tasks = (0, tasks_1.createAppleTasks)(metadataCtx, {
|
|
46
27
|
// We need to resolve a different version as soon as possible.
|
|
47
28
|
// This version is the parent model of all changes we are going to push.
|
|
@@ -71,3 +52,19 @@ async function uploadMetadataAsync(metadataCtx) {
|
|
|
71
52
|
return { appleLink: `https://appstoreconnect.apple.com/apps/${app.id}/appstore` };
|
|
72
53
|
}
|
|
73
54
|
exports.uploadMetadataAsync = uploadMetadataAsync;
|
|
55
|
+
async function loadConfigWithValidationPromptAsync(metadataCtx) {
|
|
56
|
+
try {
|
|
57
|
+
return await (0, config_1.loadConfigAsync)(metadataCtx);
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
if (error instanceof errors_1.MetadataValidationError) {
|
|
61
|
+
(0, errors_1.logMetadataValidationError)(error);
|
|
62
|
+
log_1.default.newLine();
|
|
63
|
+
log_1.default.warn('Without further updates, the current store configuration can fail to be synchronized with the App Store or pass App Store review.');
|
|
64
|
+
if (await (0, prompts_1.confirmAsync)({ message: 'Do you still want to push the store configuration?' })) {
|
|
65
|
+
return await (0, config_1.loadConfigAsync)({ ...metadataCtx, skipValidation: true });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
}
|