eas-cli 0.55.1 → 0.56.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +44 -44
  2. package/build/build/android/version.d.ts +5 -0
  3. package/build/build/android/version.js +16 -9
  4. package/build/build/build.js +7 -2
  5. package/build/build/context.d.ts +2 -3
  6. package/build/build/createContext.d.ts +3 -2
  7. package/build/build/createContext.js +2 -1
  8. package/build/build/ios/build.js +1 -16
  9. package/build/build/ios/syncProjectConfiguration.d.ts +3 -3
  10. package/build/build/ios/syncProjectConfiguration.js +2 -2
  11. package/build/build/ios/version.d.ts +10 -3
  12. package/build/build/ios/version.js +57 -28
  13. package/build/build/metadata.js +1 -1
  14. package/build/build/runBuildAndSubmit.js +7 -4
  15. package/build/commands/build/version/set.d.ts +10 -0
  16. package/build/commands/build/version/set.js +82 -0
  17. package/build/commands/build/version/sync.d.ts +12 -0
  18. package/build/commands/build/version/sync.js +124 -0
  19. package/build/commands/update/index.js +3 -1
  20. package/build/credentials/ios/types.d.ts +2 -0
  21. package/build/graphql/generated.d.ts +87 -2
  22. package/build/graphql/generated.js +1 -0
  23. package/build/graphql/mutations/AppVersionMutation.d.ts +11 -0
  24. package/build/graphql/mutations/AppVersionMutation.js +28 -0
  25. package/build/graphql/queries/AppVersionQuery.d.ts +4 -0
  26. package/build/graphql/queries/AppVersionQuery.js +37 -0
  27. package/build/platform.d.ts +1 -0
  28. package/build/platform.js +17 -1
  29. package/build/project/android/applicationId.js +2 -2
  30. package/build/project/android/versions.d.ts +3 -0
  31. package/build/project/android/versions.js +23 -0
  32. package/build/project/applicationIdentifier.d.ts +4 -0
  33. package/build/project/applicationIdentifier.js +37 -0
  34. package/build/project/ios/bundleIdentifier.js +2 -2
  35. package/build/project/ios/target.js +14 -1
  36. package/build/project/ios/versions.d.ts +3 -0
  37. package/build/project/ios/versions.js +17 -0
  38. package/build/project/publish.d.ts +1 -2
  39. package/build/project/publish.js +7 -11
  40. package/build/project/remoteVersionSource.d.ts +6 -0
  41. package/build/project/remoteVersionSource.js +52 -0
  42. package/build/submit/utils/files.d.ts +0 -6
  43. package/build/submit/utils/files.js +3 -16
  44. package/build/uploads.d.ts +8 -2
  45. package/build/uploads.js +19 -4
  46. package/oclif.manifest.json +1 -1
  47. package/package.json +8 -4
@@ -114,6 +114,7 @@ var BuildPriority;
114
114
  (function (BuildPriority) {
115
115
  BuildPriority["High"] = "HIGH";
116
116
  BuildPriority["Normal"] = "NORMAL";
117
+ BuildPriority["NormalPlus"] = "NORMAL_PLUS";
117
118
  })(BuildPriority = exports.BuildPriority || (exports.BuildPriority = {}));
118
119
  var BuildResourceClass;
119
120
  (function (BuildResourceClass) {
@@ -0,0 +1,11 @@
1
+ import { AppPlatform } from '../generated';
2
+ export declare const AppVersionMutation: {
3
+ createAppVersionAsync(appVersionInput: {
4
+ appId: string;
5
+ platform: AppPlatform;
6
+ applicationIdentifier: string;
7
+ storeVersion: string;
8
+ buildVersion: string;
9
+ runtimeVersion?: string;
10
+ }): Promise<string>;
11
+ };
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AppVersionMutation = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const assert_1 = tslib_1.__importDefault(require("assert"));
6
+ const graphql_tag_1 = tslib_1.__importDefault(require("graphql-tag"));
7
+ const client_1 = require("../client");
8
+ exports.AppVersionMutation = {
9
+ async createAppVersionAsync(appVersionInput) {
10
+ var _a;
11
+ const data = await (0, client_1.withErrorHandlingAsync)(client_1.graphqlClient
12
+ .mutation((0, graphql_tag_1.default) `
13
+ mutation CreateAppVersionMutation($appVersionInput: AppVersionInput!) {
14
+ appVersion {
15
+ createAppVersion(appVersionInput: $appVersionInput) {
16
+ id
17
+ }
18
+ }
19
+ }
20
+ `, {
21
+ appVersionInput,
22
+ })
23
+ .toPromise());
24
+ const appVersionId = (_a = data.appVersion) === null || _a === void 0 ? void 0 : _a.createAppVersion.id;
25
+ (0, assert_1.default)(appVersionId, 'AppVersion ID must be defined');
26
+ return appVersionId;
27
+ },
28
+ };
@@ -0,0 +1,4 @@
1
+ import { AppPlatform, AppVersion } from '../generated';
2
+ export declare const AppVersionQuery: {
3
+ latestVersionAsync(appId: string, platform: AppPlatform, applicationIdentifier: string): Promise<Pick<AppVersion, 'storeVersion' | 'buildVersion'> | null>;
4
+ };
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AppVersionQuery = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const graphql_tag_1 = tslib_1.__importDefault(require("graphql-tag"));
6
+ const client_1 = require("../client");
7
+ exports.AppVersionQuery = {
8
+ async latestVersionAsync(appId, platform, applicationIdentifier) {
9
+ var _a;
10
+ const data = await (0, client_1.withErrorHandlingAsync)(client_1.graphqlClient
11
+ .query((0, graphql_tag_1.default) `
12
+ query LatestAppVersion(
13
+ $appId: String!
14
+ $platform: AppPlatform!
15
+ $applicationIdentifier: String!
16
+ ) {
17
+ app {
18
+ byId(appId: $appId) {
19
+ id
20
+ latestAppVersionByPlatformAndApplicationIdentifier(
21
+ platform: $platform
22
+ applicationIdentifier: $applicationIdentifier
23
+ ) {
24
+ id
25
+ storeVersion
26
+ buildVersion
27
+ }
28
+ }
29
+ }
30
+ }
31
+ `, { appId, applicationIdentifier, platform }, {
32
+ additionalTypenames: ['App', 'AppVersion'],
33
+ })
34
+ .toPromise());
35
+ return (_a = data.app.byId.latestAppVersionByPlatformAndApplicationIdentifier) !== null && _a !== void 0 ? _a : null;
36
+ },
37
+ };
@@ -12,4 +12,5 @@ export declare enum RequestedPlatform {
12
12
  }
13
13
  export declare const requestedPlatformDisplayNames: Record<RequestedPlatform, string>;
14
14
  export declare function selectRequestedPlatformAsync(platform?: string): Promise<RequestedPlatform>;
15
+ export declare function selectPlatformAsync(platform?: string): Promise<Platform>;
15
16
  export declare function toPlatforms(requestedPlatform: RequestedPlatform): Platform[];
package/build/platform.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.toPlatforms = exports.selectRequestedPlatformAsync = exports.requestedPlatformDisplayNames = exports.RequestedPlatform = exports.appPlatformEmojis = exports.appPlatformDisplayNames = void 0;
3
+ exports.toPlatforms = exports.selectPlatformAsync = exports.selectRequestedPlatformAsync = exports.requestedPlatformDisplayNames = exports.RequestedPlatform = exports.appPlatformEmojis = exports.appPlatformDisplayNames = void 0;
4
4
  const eas_build_job_1 = require("@expo/eas-build-job");
5
5
  const generated_1 = require("./graphql/generated");
6
6
  const prompts_1 = require("./prompts");
@@ -42,6 +42,22 @@ async function selectRequestedPlatformAsync(platform) {
42
42
  return requestedPlatform;
43
43
  }
44
44
  exports.selectRequestedPlatformAsync = selectRequestedPlatformAsync;
45
+ async function selectPlatformAsync(platform) {
46
+ if (platform && Object.values(eas_build_job_1.Platform).includes(platform.toLowerCase())) {
47
+ return platform.toLowerCase();
48
+ }
49
+ const { resolvedPlatform } = await (0, prompts_1.promptAsync)({
50
+ type: 'select',
51
+ message: 'Select platform',
52
+ name: 'resolvedPlatform',
53
+ choices: [
54
+ { title: 'Android', value: eas_build_job_1.Platform.ANDROID },
55
+ { title: 'iOS', value: eas_build_job_1.Platform.IOS },
56
+ ],
57
+ });
58
+ return resolvedPlatform;
59
+ }
60
+ exports.selectPlatformAsync = selectPlatformAsync;
45
61
  function toPlatforms(requestedPlatform) {
46
62
  if (requestedPlatform === RequestedPlatform.All) {
47
63
  return [eas_build_job_1.Platform.ANDROID, eas_build_job_1.Platform.IOS];
@@ -120,8 +120,8 @@ exports.isApplicationIdValid = isApplicationIdValid;
120
120
  let warnPrinted = false;
121
121
  function warnIfAndroidPackageDefinedInAppConfigForBareWorkflowProject(projectDir, exp) {
122
122
  if (config_plugins_1.AndroidConfig.Package.getPackage(exp) && !warnPrinted) {
123
- log_1.default.warn(`Specifying "android.package" in ${(0, projectUtils_1.getProjectConfigDescription)(projectDir)} is deprecated for bare workflow projects.\n` +
124
- 'EAS Build depends only on the value in the native code. Please remove the deprecated configuration.');
123
+ log_1.default.warn(`Specified value for "android.package" in ${(0, projectUtils_1.getProjectConfigDescription)(projectDir)} is ignored because an ${chalk_1.default.bold('android')} directory was detected in the project.\n` +
124
+ 'EAS Build will use the value found in the native code.');
125
125
  warnPrinted = true;
126
126
  }
127
127
  }
@@ -0,0 +1,3 @@
1
+ export declare const VERSION_CODE_REQUIREMENTS: string;
2
+ export declare function isValidVersionCode(versionCode: string | number): boolean;
3
+ export declare function getNextVersionCode(versionCode: string | number): number;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getNextVersionCode = exports.isValidVersionCode = exports.VERSION_CODE_REQUIREMENTS = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const assert_1 = tslib_1.__importDefault(require("assert"));
6
+ const MAX_VERSION_CODE = 2000000000;
7
+ exports.VERSION_CODE_REQUIREMENTS = `versionCode needs to be a positive integer smaller or equal to ${MAX_VERSION_CODE}`;
8
+ function isValidVersionCode(versionCode) {
9
+ const numericVersionCode = typeof versionCode === 'string' ? Number(versionCode) : versionCode;
10
+ return (Number.isInteger(numericVersionCode) &&
11
+ numericVersionCode <= MAX_VERSION_CODE &&
12
+ numericVersionCode > 0);
13
+ }
14
+ exports.isValidVersionCode = isValidVersionCode;
15
+ function getNextVersionCode(versionCode) {
16
+ (0, assert_1.default)(isValidVersionCode(versionCode), `Invalid versionCode ${versionCode}`);
17
+ const numericVersionCode = typeof versionCode === 'string' ? Number(versionCode) : versionCode;
18
+ if (numericVersionCode >= MAX_VERSION_CODE) {
19
+ throw new Error(`Invalid value: ${exports.VERSION_CODE_REQUIREMENTS}.`);
20
+ }
21
+ return numericVersionCode + 1;
22
+ }
23
+ exports.getNextVersionCode = getNextVersionCode;
@@ -0,0 +1,4 @@
1
+ import { ExpoConfig } from '@expo/config';
2
+ import { Platform } from '@expo/eas-build-job';
3
+ import { BuildProfile } from '@expo/eas-json';
4
+ export declare function getApplicationIdentifierAsync(projectDir: string, exp: ExpoConfig, buildProfile: BuildProfile, platform: Platform): Promise<string>;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getApplicationIdentifierAsync = void 0;
4
+ const eas_build_job_1 = require("@expo/eas-build-job");
5
+ const applicationId_1 = require("./android/applicationId");
6
+ const gradle_1 = require("./android/gradle");
7
+ const bundleIdentifier_1 = require("./ios/bundleIdentifier");
8
+ const scheme_1 = require("./ios/scheme");
9
+ const target_1 = require("./ios/target");
10
+ const workflow_1 = require("./workflow");
11
+ async function getApplicationIdentifierAsync(projectDir, exp, buildProfile, platform) {
12
+ if (platform === eas_build_job_1.Platform.ANDROID) {
13
+ const profile = buildProfile;
14
+ const workflow = await (0, workflow_1.resolveWorkflowAsync)(projectDir, eas_build_job_1.Platform.ANDROID);
15
+ const gradleContext = await (0, gradle_1.resolveGradleBuildContextAsync)(projectDir, profile);
16
+ if (workflow === eas_build_job_1.Workflow.MANAGED) {
17
+ await (0, applicationId_1.ensureApplicationIdIsDefinedForManagedProjectAsync)(projectDir, exp);
18
+ }
19
+ return await (0, applicationId_1.getApplicationIdAsync)(projectDir, exp, gradleContext);
20
+ }
21
+ else {
22
+ const profile = buildProfile;
23
+ const xcodeBuildContext = await (0, scheme_1.resolveXcodeBuildContextAsync)({ exp, projectDir, nonInteractive: false }, profile);
24
+ const targets = await (0, target_1.resolveTargetsAsync)({
25
+ projectDir,
26
+ exp,
27
+ xcodeBuildContext,
28
+ env: profile.env,
29
+ });
30
+ const applicationTarget = (0, target_1.findApplicationTarget)(targets);
31
+ return await (0, bundleIdentifier_1.getBundleIdentifierAsync)(projectDir, exp, {
32
+ targetName: applicationTarget.targetName,
33
+ buildConfiguration: applicationTarget.buildConfiguration,
34
+ });
35
+ }
36
+ }
37
+ exports.getApplicationIdentifierAsync = getApplicationIdentifierAsync;
@@ -104,8 +104,8 @@ exports.isBundleIdentifierValid = isBundleIdentifierValid;
104
104
  let warnPrinted = false;
105
105
  function warnIfBundleIdentifierDefinedInAppConfigForBareWorkflowProject(projectDir, exp) {
106
106
  if (config_plugins_1.IOSConfig.BundleIdentifier.getBundleIdentifier(exp) && !warnPrinted) {
107
- log_1.default.warn(`Specifying "ios.bundleIdentifier" in ${(0, projectUtils_1.getProjectConfigDescription)(projectDir)} is deprecated for bare workflow projects.\n` +
108
- 'EAS Build depends only on the value in the native code. Please remove the deprecated configuration.');
107
+ log_1.default.warn(`Specified value for "ios.bundleIdentifier" in ${(0, projectUtils_1.getProjectConfigDescription)(projectDir)} is ignored because an ${chalk_1.default.bold('ios')} directory was detected in the project.\n` +
108
+ 'EAS Build will use the value found in the native code.');
109
109
  warnPrinted = true;
110
110
  }
111
111
  }
@@ -55,6 +55,7 @@ exports.resolveMangedProjectTargetsAsync = resolveMangedProjectTargetsAsync;
55
55
  async function resolveBareProjectTargetsAsync({ exp, projectDir, xcodeBuildContext, }) {
56
56
  const { buildScheme, buildConfiguration } = xcodeBuildContext;
57
57
  const result = [];
58
+ const pbxProject = config_plugins_1.IOSConfig.XcodeUtils.getPbxproj(projectDir);
58
59
  const applicationTarget = await config_plugins_1.IOSConfig.Target.findApplicationTargetWithDependenciesAsync(projectDir, buildScheme);
59
60
  const bundleIdentifier = await (0, bundleIdentifier_1.getBundleIdentifierAsync)(projectDir, exp, {
60
61
  targetName: applicationTarget.name,
@@ -69,6 +70,7 @@ async function resolveBareProjectTargetsAsync({ exp, projectDir, xcodeBuildConte
69
70
  bundleIdentifier,
70
71
  buildConfiguration,
71
72
  entitlements: entitlements !== null && entitlements !== void 0 ? entitlements : {},
73
+ buildSettings: resolveBareProjectBuildSettings(pbxProject, applicationTarget.name, buildConfiguration),
72
74
  });
73
75
  const dependencies = await resolveBareProjectDependenciesAsync({
74
76
  exp,
@@ -76,6 +78,7 @@ async function resolveBareProjectTargetsAsync({ exp, projectDir, xcodeBuildConte
76
78
  buildConfiguration,
77
79
  target: applicationTarget,
78
80
  bundleIdentifier,
81
+ pbxProject,
79
82
  });
80
83
  if (dependencies.length > 0) {
81
84
  result.push(...dependencies);
@@ -96,7 +99,7 @@ async function resolveTargetsAsync(opts) {
96
99
  }
97
100
  }
98
101
  exports.resolveTargetsAsync = resolveTargetsAsync;
99
- async function resolveBareProjectDependenciesAsync({ exp, projectDir, buildConfiguration, target, bundleIdentifier, }) {
102
+ async function resolveBareProjectDependenciesAsync({ exp, projectDir, buildConfiguration, target, bundleIdentifier, pbxProject, }) {
100
103
  const result = [];
101
104
  if (target.dependencies && target.dependencies.length > 0) {
102
105
  for (const dependency of target.dependencies) {
@@ -114,6 +117,7 @@ async function resolveBareProjectDependenciesAsync({ exp, projectDir, buildConfi
114
117
  bundleIdentifier: dependencyBundleIdentifier,
115
118
  parentBundleIdentifier: bundleIdentifier,
116
119
  entitlements: entitlements !== null && entitlements !== void 0 ? entitlements : {},
120
+ buildSettings: resolveBareProjectBuildSettings(pbxProject, dependency.name, buildConfiguration),
117
121
  });
118
122
  const dependencyDependencies = await resolveBareProjectDependenciesAsync({
119
123
  exp,
@@ -121,6 +125,7 @@ async function resolveBareProjectDependenciesAsync({ exp, projectDir, buildConfi
121
125
  buildConfiguration,
122
126
  target: dependency,
123
127
  bundleIdentifier: dependencyBundleIdentifier,
128
+ pbxProject,
124
129
  });
125
130
  if (dependencyDependencies.length > 0) {
126
131
  result.push(...dependencyDependencies);
@@ -145,3 +150,11 @@ function findTargetByName(targets, name) {
145
150
  return target;
146
151
  }
147
152
  exports.findTargetByName = findTargetByName;
153
+ function resolveBareProjectBuildSettings(project, targetName, buildConfiguration) {
154
+ var _a;
155
+ const xcBuildConfiguration = config_plugins_1.IOSConfig.Target.getXCBuildConfigurationFromPbxproj(project, {
156
+ targetName,
157
+ buildConfiguration,
158
+ });
159
+ return (_a = xcBuildConfiguration === null || xcBuildConfiguration === void 0 ? void 0 : xcBuildConfiguration.buildSettings) !== null && _a !== void 0 ? _a : {};
160
+ }
@@ -0,0 +1,3 @@
1
+ export declare const BUILD_NUMBER_REQUIREMENTS = "buildNumber needs to consist only of up to 3 dot-separated positive integers";
2
+ export declare function isValidBuildNumber(buildNumber: string): boolean;
3
+ export declare function getNextBuildNumber(buildNumber: string): string;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getNextBuildNumber = exports.isValidBuildNumber = exports.BUILD_NUMBER_REQUIREMENTS = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const assert_1 = tslib_1.__importDefault(require("assert"));
6
+ exports.BUILD_NUMBER_REQUIREMENTS = `buildNumber needs to consist only of up to 3 dot-separated positive integers`;
7
+ function isValidBuildNumber(buildNumber) {
8
+ return !!buildNumber.match(/^\d+(\.\d+)?(\.\d+)?$/);
9
+ }
10
+ exports.isValidBuildNumber = isValidBuildNumber;
11
+ function getNextBuildNumber(buildNumber) {
12
+ (0, assert_1.default)(isValidBuildNumber(buildNumber), `Invalid buildNumber ${buildNumber}`);
13
+ const comps = buildNumber.split('.');
14
+ comps[comps.length - 1] = String(Number(comps[comps.length - 1]) + 1);
15
+ return comps.join('.');
16
+ }
17
+ exports.getNextBuildNumber = getNextBuildNumber;
@@ -2,7 +2,6 @@
2
2
  import { ExpoConfig, Platform } from '@expo/config';
3
3
  import Joi from 'joi';
4
4
  import { PartialManifestAsset } from '../graphql/generated';
5
- export declare const TIMEOUT_LIMIT = 60000;
6
5
  export declare type PublishPlatform = Extract<'android' | 'ios', Platform>;
7
6
  declare type Metadata = {
8
7
  version: number;
@@ -78,5 +77,5 @@ declare type AssetUploadResult = {
78
77
  uniqueAssetCount: number;
79
78
  uniqueUploadedAssetCount: number;
80
79
  };
81
- export declare function uploadAssetsAsync(assetsForUpdateInfoGroup: CollectedAssets, updateSpinnerText?: (updatedText: string) => void): Promise<AssetUploadResult>;
80
+ export declare function uploadAssetsAsync(assetsForUpdateInfoGroup: CollectedAssets, updateSpinnerText?: (totalAssets: number, missingAssets: number) => void): Promise<AssetUploadResult>;
82
81
  export {};
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.uploadAssetsAsync = exports.filterOutAssetsThatAlreadyExistAsync = exports.collectAssetsAsync = exports.loadMetadata = exports.resolveInputDirectoryAsync = exports.buildBundlesAsync = exports.buildUnsortedUpdateInfoGroupAsync = exports.convertAssetToUpdateInfoGroupFormatAsync = exports.getStorageKeyForAssetAsync = exports.getStorageKey = exports.getBase64URLEncoding = exports.guessContentTypeFromExtension = exports.MetadataJoi = exports.TIMEOUT_LIMIT = void 0;
3
+ exports.uploadAssetsAsync = exports.filterOutAssetsThatAlreadyExistAsync = exports.collectAssetsAsync = exports.loadMetadata = exports.resolveInputDirectoryAsync = exports.buildBundlesAsync = exports.buildUnsortedUpdateInfoGroupAsync = exports.convertAssetToUpdateInfoGroupFormatAsync = exports.getStorageKeyForAssetAsync = exports.getStorageKey = exports.getBase64URLEncoding = exports.guessContentTypeFromExtension = exports.MetadataJoi = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const json_file_1 = tslib_1.__importDefault(require("@expo/json-file"));
6
6
  const crypto_1 = tslib_1.__importDefault(require("crypto"));
@@ -15,7 +15,6 @@ const PublishQuery_1 = require("../graphql/queries/PublishQuery");
15
15
  const uploads_1 = require("../uploads");
16
16
  const expoCli_1 = require("../utils/expoCli");
17
17
  const uniqBy_1 = tslib_1.__importDefault(require("../utils/expodash/uniqBy"));
18
- exports.TIMEOUT_LIMIT = 60000; // 1 minute
19
18
  const fileMetadataJoi = joi_1.default.object({
20
19
  assets: joi_1.default.array()
21
20
  .required()
@@ -113,6 +112,7 @@ async function buildBundlesAsync({ projectDir, inputDir, }) {
113
112
  inputDir,
114
113
  '--experimental-bundle',
115
114
  '--non-interactive',
115
+ '--dump-sourcemap',
116
116
  ]);
117
117
  }
118
118
  exports.buildBundlesAsync = buildBundlesAsync;
@@ -194,7 +194,6 @@ async function uploadAssetsAsync(assetsForUpdateInfoGroup, updateSpinnerText) {
194
194
  ...assetsForUpdateInfoGroup[platform].assets,
195
195
  ];
196
196
  }
197
- updateSpinnerText === null || updateSpinnerText === void 0 ? void 0 : updateSpinnerText(`${assets.length} ${assets.length === 1 ? 'asset' : 'assets'} present`);
198
197
  const assetsWithStorageKey = await Promise.all(assets.map(async (asset) => {
199
198
  return {
200
199
  ...asset,
@@ -202,10 +201,12 @@ async function uploadAssetsAsync(assetsForUpdateInfoGroup, updateSpinnerText) {
202
201
  };
203
202
  }));
204
203
  const uniqueAssets = (0, uniqBy_1.default)(assetsWithStorageKey, asset => asset.storageKey);
205
- updateSpinnerText === null || updateSpinnerText === void 0 ? void 0 : updateSpinnerText(`${uniqueAssets.length} unique ${uniqueAssets.length === 1 ? 'asset' : 'assets'} found`);
204
+ const totalAssets = uniqueAssets.length;
205
+ updateSpinnerText === null || updateSpinnerText === void 0 ? void 0 : updateSpinnerText(totalAssets, totalAssets);
206
206
  let missingAssets = await filterOutAssetsThatAlreadyExistAsync(uniqueAssets);
207
207
  const uniqueUploadedAssetCount = missingAssets.length;
208
208
  const { specifications } = await PublishMutation_1.PublishMutation.getUploadURLsAsync(missingAssets.map(ma => ma.contentType));
209
+ updateSpinnerText === null || updateSpinnerText === void 0 ? void 0 : updateSpinnerText(totalAssets, missingAssets.length);
209
210
  const assetUploadPromiseLimit = (0, promise_limit_1.default)(15);
210
211
  await Promise.all(missingAssets.map((missingAsset, i) => {
211
212
  assetUploadPromiseLimit(async () => {
@@ -213,18 +214,13 @@ async function uploadAssetsAsync(assetsForUpdateInfoGroup, updateSpinnerText) {
213
214
  await (0, uploads_1.uploadWithPresignedPostAsync)(missingAsset.path, presignedPost);
214
215
  });
215
216
  }));
216
- updateSpinnerText === null || updateSpinnerText === void 0 ? void 0 : updateSpinnerText(`${missingAssets.length} new ${missingAssets.length === 1 ? 'asset' : 'assets'} uploading`);
217
- // Wait up to TIMEOUT_LIMIT for assets to be uploaded and processed
218
- const start = Date.now();
219
217
  let timeout = 1;
220
218
  while (missingAssets.length > 0) {
221
- const timeoutPromise = new Promise(resolve => setTimeout(resolve, timeout * 1000)); // linear backoff
219
+ const timeoutPromise = new Promise(resolve => setTimeout(resolve, Math.min(timeout * 1000, 5000))); // linear backoff
222
220
  missingAssets = await filterOutAssetsThatAlreadyExistAsync(missingAssets);
223
221
  await timeoutPromise; // await after filterOutAssetsThatAlreadyExistAsync for easy mocking with jest.runAllTimers
224
222
  timeout += 1;
225
- if (Date.now() - start > exports.TIMEOUT_LIMIT) {
226
- throw new Error('Asset upload timed out. Please try again.');
227
- }
223
+ updateSpinnerText === null || updateSpinnerText === void 0 ? void 0 : updateSpinnerText(totalAssets, missingAssets.length);
228
224
  }
229
225
  return {
230
226
  assetCount: assets.length,
@@ -0,0 +1,6 @@
1
+ import { ExpoConfig } from '@expo/config';
2
+ import { Platform } from '@expo/eas-build-job';
3
+ import { EasJsonReader } from '@expo/eas-json';
4
+ export declare function ensureRemoteVersionPolicyAsync(projectDir: string, easJsonReader: EasJsonReader): Promise<void>;
5
+ export declare function validateAppConfigForRemoteVersionPolicyAsync(exp: ExpoConfig): Promise<void>;
6
+ export declare function getBuildVersionName(platform: Platform): string;
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getBuildVersionName = exports.validateAppConfigForRemoteVersionPolicyAsync = exports.ensureRemoteVersionPolicyAsync = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const eas_build_job_1 = require("@expo/eas-build-job");
6
+ const eas_json_1 = require("@expo/eas-json");
7
+ const chalk_1 = tslib_1.__importDefault(require("chalk"));
8
+ const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
9
+ const log_1 = tslib_1.__importDefault(require("../log"));
10
+ const prompts_1 = require("../prompts");
11
+ async function ensureRemoteVersionPolicyAsync(projectDir, easJsonReader) {
12
+ const easJsonCliConfig = await easJsonReader.getCliConfigAsync();
13
+ if ((easJsonCliConfig === null || easJsonCliConfig === void 0 ? void 0 : easJsonCliConfig.appVersionSource) === eas_json_1.AppVersionSource.REMOTE) {
14
+ return;
15
+ }
16
+ log_1.default.log(`The app version source defines whether the app version is stored locally in your project source (e.g. in app.json, Info.plist, or build.gradle) or remotely on EAS servers and only applied to the project at build time. To use this command, you will need to enable the remote version policy by adding ${chalk_1.default.bold('{"cli": { "appVersionSource": "remote" }}')} in eas.json.`);
17
+ // TODO: add link to docs
18
+ const confirm = await (0, prompts_1.confirmAsync)({
19
+ message: 'Do you want to set app version source to remote now?',
20
+ });
21
+ if (!confirm) {
22
+ throw new Error('Aborting...');
23
+ }
24
+ const easJsonPath = eas_json_1.EasJsonReader.formatEasJsonPath(projectDir);
25
+ const easJson = await fs_extra_1.default.readJSON(easJsonPath);
26
+ easJson.cli = { ...easJson === null || easJson === void 0 ? void 0 : easJson.cli, appVersionSource: eas_json_1.AppVersionSource.REMOTE };
27
+ await fs_extra_1.default.writeFile(easJsonPath, `${JSON.stringify(easJson, null, 2)}\n`);
28
+ log_1.default.withTick('Updated eas.json');
29
+ }
30
+ exports.ensureRemoteVersionPolicyAsync = ensureRemoteVersionPolicyAsync;
31
+ async function validateAppConfigForRemoteVersionPolicyAsync(exp) {
32
+ var _a, _b, _c;
33
+ if (typeof exp.runtimeVersion === 'object' && ((_a = exp.runtimeVersion) === null || _a === void 0 ? void 0 : _a.policy) === 'nativeVersion') {
34
+ throw new Error(`${chalk_1.default.bold('nativeVersion')} policy for ${chalk_1.default.bold('runtimeVersion')} is currently not supported when version source is set to remote. Switch policy e.g. to ${chalk_1.default.bold('appVersion')} or define version explicitly.`);
35
+ }
36
+ if (((_b = exp.ios) === null || _b === void 0 ? void 0 : _b.buildNumber) !== undefined) {
37
+ throw new Error(`${chalk_1.default.bold('ios.buildNumber')} field in app config is not supported when version source is set to remote, remove it and re-run the command.`);
38
+ }
39
+ if (((_c = exp.android) === null || _c === void 0 ? void 0 : _c.versionCode) !== undefined) {
40
+ throw new Error(`${chalk_1.default.bold('android.versionCode')} field in app config is not supported when version source is set to remote, remove it and re-run the command.`);
41
+ }
42
+ }
43
+ exports.validateAppConfigForRemoteVersionPolicyAsync = validateAppConfigForRemoteVersionPolicyAsync;
44
+ function getBuildVersionName(platform) {
45
+ if (platform === eas_build_job_1.Platform.ANDROID) {
46
+ return 'versionCode';
47
+ }
48
+ else {
49
+ return 'buildNumber';
50
+ }
51
+ }
52
+ exports.getBuildVersionName = getBuildVersionName;
@@ -1,8 +1,2 @@
1
1
  export declare function isExistingFileAsync(filePath: string): Promise<boolean>;
2
2
  export declare function uploadAppArchiveAsync(path: string): Promise<string>;
3
- /**
4
- * S3 returns broken URLs, sth like:
5
- * https://submission-service-archives.s3.amazonaws.com/production%2Fdc98ca84-1473-4cb3-ae81-8c7b291cb27e%2F4424aa95-b985-4e2f-8755-9507b1037c1c
6
- * This function replaces %2F with /.
7
- */
8
- export declare function fixArchiveUrl(archiveUrl: string): string;
@@ -1,9 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.fixArchiveUrl = exports.uploadAppArchiveAsync = exports.isExistingFileAsync = void 0;
3
+ exports.uploadAppArchiveAsync = exports.isExistingFileAsync = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
6
- const url_1 = require("url");
7
6
  const generated_1 = require("../../graphql/generated");
8
7
  const uploads_1 = require("../../uploads");
9
8
  const progress_1 = require("../../utils/progress");
@@ -19,23 +18,11 @@ async function isExistingFileAsync(filePath) {
19
18
  exports.isExistingFileAsync = isExistingFileAsync;
20
19
  async function uploadAppArchiveAsync(path) {
21
20
  const fileSize = (await fs_extra_1.default.stat(path)).size;
22
- const { response } = await (0, uploads_1.uploadAsync)(generated_1.UploadSessionType.EasSubmitAppArchive, path, (0, progress_1.createProgressTracker)({
21
+ const { url } = await (0, uploads_1.uploadFileAtPathToS3Async)(generated_1.UploadSessionType.EasSubmitAppArchive, path, (0, progress_1.createProgressTracker)({
23
22
  total: fileSize,
24
23
  message: 'Uploading to EAS Submit',
25
24
  completedMessage: 'Uploaded to EAS Submit',
26
25
  }));
27
- const url = response.headers.get('location');
28
- return fixArchiveUrl(String(url));
26
+ return url;
29
27
  }
30
28
  exports.uploadAppArchiveAsync = uploadAppArchiveAsync;
31
- /**
32
- * S3 returns broken URLs, sth like:
33
- * https://submission-service-archives.s3.amazonaws.com/production%2Fdc98ca84-1473-4cb3-ae81-8c7b291cb27e%2F4424aa95-b985-4e2f-8755-9507b1037c1c
34
- * This function replaces %2F with /.
35
- */
36
- function fixArchiveUrl(archiveUrl) {
37
- const parsed = new url_1.URL(archiveUrl);
38
- parsed.pathname = decodeURIComponent(parsed.pathname);
39
- return parsed.toString();
40
- }
41
- exports.fixArchiveUrl = fixArchiveUrl;
@@ -2,8 +2,14 @@ import { Response } from 'node-fetch';
2
2
  import { UploadSessionType } from './graphql/generated';
3
3
  import { PresignedPost } from './graphql/mutations/UploadSessionMutation';
4
4
  import { ProgressHandler } from './utils/progress';
5
- export declare function uploadAsync(type: UploadSessionType, path: string, handleProgressEvent: ProgressHandler): Promise<{
6
- response: Response;
5
+ export declare function uploadFileAtPathToS3Async(type: UploadSessionType, path: string, handleProgressEvent: ProgressHandler): Promise<{
6
+ url: string;
7
7
  bucketKey: string;
8
8
  }>;
9
9
  export declare function uploadWithPresignedPostAsync(file: string, presignedPost: PresignedPost, handleProgressEvent?: ProgressHandler): Promise<Response>;
10
+ /**
11
+ * S3 returns broken URLs, sth like:
12
+ * https://submission-service-archives.s3.amazonaws.com/production%2Fdc98ca84-1473-4cb3-ae81-8c7b291cb27e%2F4424aa95-b985-4e2f-8755-9507b1037c1c
13
+ * This function replaces %2F with /.
14
+ */
15
+ export declare function fixS3Url(archiveUrl: string): string;
package/build/uploads.js CHANGED
@@ -1,19 +1,23 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.uploadWithPresignedPostAsync = exports.uploadAsync = void 0;
3
+ exports.fixS3Url = exports.uploadWithPresignedPostAsync = exports.uploadFileAtPathToS3Async = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const assert_1 = tslib_1.__importDefault(require("assert"));
6
6
  const form_data_1 = tslib_1.__importDefault(require("form-data"));
7
7
  const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
8
+ const nullthrows_1 = tslib_1.__importDefault(require("nullthrows"));
9
+ const url_1 = require("url");
8
10
  const fetch_1 = tslib_1.__importDefault(require("./fetch"));
9
11
  const UploadSessionMutation_1 = require("./graphql/mutations/UploadSessionMutation");
10
- async function uploadAsync(type, path, handleProgressEvent) {
12
+ async function uploadFileAtPathToS3Async(type, path, handleProgressEvent) {
11
13
  const presignedPost = await UploadSessionMutation_1.UploadSessionMutation.createUploadSessionAsync(type);
12
14
  (0, assert_1.default)(presignedPost.fields.key, 'key is not specified in in presigned post');
13
15
  const response = await uploadWithPresignedPostAsync(path, presignedPost, handleProgressEvent);
14
- return { response, bucketKey: presignedPost.fields.key };
16
+ const location = (0, nullthrows_1.default)(response.headers.get('location'), `location does not exist in response headers (make sure you're uploading to AWS S3)`);
17
+ const url = fixS3Url(location);
18
+ return { url, bucketKey: presignedPost.fields.key };
15
19
  }
16
- exports.uploadAsync = uploadAsync;
20
+ exports.uploadFileAtPathToS3Async = uploadFileAtPathToS3Async;
17
21
  async function uploadWithPresignedPostAsync(file, presignedPost, handleProgressEvent) {
18
22
  const fileStat = await fs_extra_1.default.stat(file);
19
23
  const fileSize = fileStat.size;
@@ -57,3 +61,14 @@ async function uploadWithPresignedPostAsync(file, presignedPost, handleProgressE
57
61
  }
58
62
  }
59
63
  exports.uploadWithPresignedPostAsync = uploadWithPresignedPostAsync;
64
+ /**
65
+ * S3 returns broken URLs, sth like:
66
+ * https://submission-service-archives.s3.amazonaws.com/production%2Fdc98ca84-1473-4cb3-ae81-8c7b291cb27e%2F4424aa95-b985-4e2f-8755-9507b1037c1c
67
+ * This function replaces %2F with /.
68
+ */
69
+ function fixS3Url(archiveUrl) {
70
+ const parsed = new url_1.URL(archiveUrl);
71
+ parsed.pathname = decodeURIComponent(parsed.pathname);
72
+ return parsed.toString();
73
+ }
74
+ exports.fixS3Url = fixS3Url;