eas-cli 0.54.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 (74) hide show
  1. package/README.md +44 -44
  2. package/build/build/android/build.js +2 -1
  3. package/build/build/android/version.d.ts +5 -0
  4. package/build/build/android/version.js +16 -9
  5. package/build/build/build.d.ts +2 -2
  6. package/build/build/build.js +16 -5
  7. package/build/build/context.d.ts +4 -3
  8. package/build/build/createContext.d.ts +5 -2
  9. package/build/build/createContext.js +3 -1
  10. package/build/build/ios/build.js +3 -17
  11. package/build/build/ios/syncProjectConfiguration.d.ts +3 -3
  12. package/build/build/ios/syncProjectConfiguration.js +2 -2
  13. package/build/build/ios/version.d.ts +10 -3
  14. package/build/build/ios/version.js +57 -28
  15. package/build/build/metadata.js +1 -1
  16. package/build/build/runBuildAndSubmit.d.ts +2 -0
  17. package/build/build/runBuildAndSubmit.js +19 -3
  18. package/build/build/types.d.ts +4 -0
  19. package/build/build/types.js +6 -1
  20. package/build/commands/build/index.d.ts +2 -0
  21. package/build/commands/build/index.js +8 -1
  22. package/build/commands/build/version/set.d.ts +10 -0
  23. package/build/commands/build/version/set.js +82 -0
  24. package/build/commands/build/version/sync.d.ts +12 -0
  25. package/build/commands/build/version/sync.js +124 -0
  26. package/build/commands/update/index.d.ts +1 -0
  27. package/build/commands/update/index.js +15 -4
  28. package/build/credentials/ios/types.d.ts +2 -0
  29. package/build/env.d.ts +11 -0
  30. package/build/env.js +12 -0
  31. package/build/graphql/generated.d.ts +102 -2
  32. package/build/graphql/generated.js +10 -1
  33. package/build/graphql/mutations/AppVersionMutation.d.ts +11 -0
  34. package/build/graphql/mutations/AppVersionMutation.js +28 -0
  35. package/build/graphql/mutations/BuildMutation.d.ts +3 -1
  36. package/build/graphql/mutations/BuildMutation.js +14 -2
  37. package/build/graphql/queries/AppVersionQuery.d.ts +4 -0
  38. package/build/graphql/queries/AppVersionQuery.js +37 -0
  39. package/build/graphql/queries/WebhookQuery.d.ts +1 -1
  40. package/build/metadata/apple/config/reader.d.ts +2 -1
  41. package/build/metadata/apple/config/reader.js +66 -9
  42. package/build/metadata/apple/config/writer.d.ts +3 -2
  43. package/build/metadata/apple/config/writer.js +64 -12
  44. package/build/metadata/apple/data.d.ts +2 -1
  45. package/build/metadata/apple/tasks/app-review-detail.d.ts +14 -0
  46. package/build/metadata/apple/tasks/app-review-detail.js +49 -0
  47. package/build/metadata/apple/tasks/app-version.js +2 -2
  48. package/build/metadata/apple/tasks/index.js +2 -1
  49. package/build/metadata/apple/types.d.ts +9 -11
  50. package/build/metadata/errors.d.ts +5 -0
  51. package/build/metadata/errors.js +18 -9
  52. package/build/metadata/upload.js +13 -3
  53. package/build/platform.d.ts +1 -0
  54. package/build/platform.js +17 -1
  55. package/build/project/android/applicationId.js +6 -2
  56. package/build/project/android/versions.d.ts +3 -0
  57. package/build/project/android/versions.js +23 -0
  58. package/build/project/applicationIdentifier.d.ts +4 -0
  59. package/build/project/applicationIdentifier.js +37 -0
  60. package/build/project/ios/bundleIdentifier.js +2 -2
  61. package/build/project/ios/target.js +14 -1
  62. package/build/project/ios/versions.d.ts +3 -0
  63. package/build/project/ios/versions.js +17 -0
  64. package/build/project/publish.d.ts +1 -2
  65. package/build/project/publish.js +15 -14
  66. package/build/project/remoteVersionSource.d.ts +6 -0
  67. package/build/project/remoteVersionSource.js +52 -0
  68. package/build/project/workflow.js +13 -11
  69. package/build/submit/utils/files.js +1 -1
  70. package/build/uploads.d.ts +9 -2
  71. package/build/uploads.js +21 -7
  72. package/oclif.manifest.json +1 -1
  73. package/package.json +9 -5
  74. package/schema/metadata-0.json +396 -336
@@ -16,21 +16,43 @@ class AppleConfigReader {
16
16
  this.schema = schema;
17
17
  }
18
18
  getAgeRating() {
19
- return this.schema.advisory || null;
19
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
20
+ const attributes = this.schema.advisory;
21
+ if (!attributes) {
22
+ return null;
23
+ }
24
+ return {
25
+ alcoholTobaccoOrDrugUseOrReferences: (_a = attributes.alcoholTobaccoOrDrugUseOrReferences) !== null && _a !== void 0 ? _a : apple_utils_1.Rating.NONE,
26
+ contests: (_b = attributes.contests) !== null && _b !== void 0 ? _b : apple_utils_1.Rating.NONE,
27
+ gamblingSimulated: (_c = attributes.gamblingSimulated) !== null && _c !== void 0 ? _c : apple_utils_1.Rating.NONE,
28
+ horrorOrFearThemes: (_d = attributes.horrorOrFearThemes) !== null && _d !== void 0 ? _d : apple_utils_1.Rating.NONE,
29
+ matureOrSuggestiveThemes: (_e = attributes.matureOrSuggestiveThemes) !== null && _e !== void 0 ? _e : apple_utils_1.Rating.NONE,
30
+ medicalOrTreatmentInformation: (_f = attributes.medicalOrTreatmentInformation) !== null && _f !== void 0 ? _f : apple_utils_1.Rating.NONE,
31
+ profanityOrCrudeHumor: (_g = attributes.profanityOrCrudeHumor) !== null && _g !== void 0 ? _g : apple_utils_1.Rating.NONE,
32
+ sexualContentGraphicAndNudity: (_h = attributes.sexualContentGraphicAndNudity) !== null && _h !== void 0 ? _h : apple_utils_1.Rating.NONE,
33
+ sexualContentOrNudity: (_j = attributes.sexualContentOrNudity) !== null && _j !== void 0 ? _j : apple_utils_1.Rating.NONE,
34
+ violenceCartoonOrFantasy: (_k = attributes.violenceCartoonOrFantasy) !== null && _k !== void 0 ? _k : apple_utils_1.Rating.NONE,
35
+ violenceRealistic: (_l = attributes.violenceRealistic) !== null && _l !== void 0 ? _l : apple_utils_1.Rating.NONE,
36
+ violenceRealisticProlongedGraphicOrSadistic: (_m = attributes.violenceRealisticProlongedGraphicOrSadistic) !== null && _m !== void 0 ? _m : apple_utils_1.Rating.NONE,
37
+ gambling: (_o = attributes.gambling) !== null && _o !== void 0 ? _o : false,
38
+ unrestrictedWebAccess: (_p = attributes.unrestrictedWebAccess) !== null && _p !== void 0 ? _p : false,
39
+ kidsAgeBand: (_q = attributes.kidsAgeBand) !== null && _q !== void 0 ? _q : null,
40
+ seventeenPlus: (_r = attributes.seventeenPlus) !== null && _r !== void 0 ? _r : false,
41
+ };
20
42
  }
21
43
  getLocales() {
22
44
  // TODO: filter "default" locales, add option to add non-localized info to the config
23
45
  return (0, uniq_1.default)(Object.keys(this.schema.info || {}));
24
46
  }
25
47
  getInfoLocale(locale) {
26
- var _a, _b;
48
+ var _a;
27
49
  const info = (_a = this.schema.info) === null || _a === void 0 ? void 0 : _a[locale];
28
50
  if (!info) {
29
51
  return null;
30
52
  }
31
53
  return {
32
54
  locale,
33
- name: (_b = info.title) !== null && _b !== void 0 ? _b : 'no name provided',
55
+ name: info.title,
34
56
  subtitle: info.subtitle,
35
57
  privacyChoicesUrl: info.privacyChoicesUrl,
36
58
  privacyPolicyText: info.privacyPolicyText,
@@ -38,13 +60,31 @@ class AppleConfigReader {
38
60
  };
39
61
  }
40
62
  getCategories() {
41
- if (Array.isArray(this.schema.categories) && this.schema.categories.length > 0) {
42
- return {
43
- primaryCategory: this.schema.categories[0],
44
- secondaryCategory: this.schema.categories[1],
45
- };
63
+ const { categories } = this.schema;
64
+ if (!categories || categories.length <= 0) {
65
+ return null;
46
66
  }
47
- return null;
67
+ // We validate the categories based on enums, but they will still be strings here.
68
+ const categoryIds = {};
69
+ if (Array.isArray(categories[0])) {
70
+ categoryIds.primaryCategory = categories[0][0];
71
+ categoryIds.primarySubcategoryOne = categories[0][1];
72
+ categoryIds.primarySubcategoryTwo = categories[0][2];
73
+ }
74
+ else {
75
+ categoryIds.primaryCategory = categories[0];
76
+ }
77
+ if (Array.isArray(categories[1])) {
78
+ categoryIds.secondaryCategory = categories[1][0];
79
+ categoryIds.secondarySubcategoryOne = categories[1][1];
80
+ categoryIds.secondarySubcategoryTwo = categories[1][2];
81
+ }
82
+ else {
83
+ categoryIds.secondaryCategory = categories[1];
84
+ }
85
+ // Because we handle categories as normal strings,
86
+ // the type doesn't match with the actual CategoryIds types.
87
+ return categoryIds;
48
88
  }
49
89
  /** Get the `AppStoreVersion` object. */
50
90
  getVersion() {
@@ -91,5 +131,22 @@ class AppleConfigReader {
91
131
  supportUrl: info.supportUrl,
92
132
  };
93
133
  }
134
+ getReviewDetails() {
135
+ const review = this.schema.review;
136
+ if (!review) {
137
+ return null;
138
+ }
139
+ return {
140
+ contactFirstName: review.firstName,
141
+ contactLastName: review.lastName,
142
+ contactEmail: review.email,
143
+ contactPhone: review.phone,
144
+ demoAccountName: review.demoUsername,
145
+ demoAccountPassword: review.demoPassword,
146
+ demoAccountRequired: review.demoRequired,
147
+ notes: review.notes,
148
+ // TODO: add attachment
149
+ };
150
+ }
94
151
  }
95
152
  exports.AppleConfigReader = AppleConfigReader;
@@ -1,5 +1,5 @@
1
1
  /// <reference types="@expo/apple-utils/ts-declarations/expo__app-store" />
2
- import { AgeRatingDeclaration, AppInfo, AppInfoLocalization, AppStoreVersion, AppStoreVersionLocalization } from '@expo/apple-utils';
2
+ import { AgeRatingDeclaration, AppInfo, AppInfoLocalization, AppStoreReviewDetail, AppStoreVersion, AppStoreVersionLocalization } from '@expo/apple-utils';
3
3
  import { AttributesOf } from '../../utils/asc';
4
4
  import { AppleMetadata } from '../types';
5
5
  /**
@@ -16,8 +16,9 @@ export declare class AppleConfigWriter {
16
16
  };
17
17
  setAgeRating(attributes: AttributesOf<AgeRatingDeclaration>): void;
18
18
  setInfoLocale(attributes: AttributesOf<AppInfoLocalization>): void;
19
- setCategories({ primaryCategory, secondaryCategory }: AttributesOf<AppInfo>): void;
19
+ setCategories(attributes: Pick<AttributesOf<AppInfo>, 'primaryCategory' | 'primarySubcategoryOne' | 'primarySubcategoryTwo' | 'secondaryCategory' | 'secondarySubcategoryOne' | 'secondarySubcategoryTwo'>): void;
20
20
  setVersion(attributes: Omit<AttributesOf<AppStoreVersion>, 'releaseType' | 'earliestReleaseDate'>): void;
21
21
  setVersionRelease(attributes: Pick<AttributesOf<AppStoreVersion>, 'releaseType' | 'earliestReleaseDate'>): void;
22
22
  setVersionLocale(attributes: AttributesOf<AppStoreVersionLocalization>): void;
23
+ setReviewDetails(attributes: AttributesOf<AppStoreReviewDetail>): void;
23
24
  }
@@ -18,7 +18,25 @@ class AppleConfigWriter {
18
18
  };
19
19
  }
20
20
  setAgeRating(attributes) {
21
- this.schema.advisory = attributes;
21
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
22
+ this.schema.advisory = {
23
+ alcoholTobaccoOrDrugUseOrReferences: (_a = attributes.alcoholTobaccoOrDrugUseOrReferences) !== null && _a !== void 0 ? _a : apple_utils_1.Rating.NONE,
24
+ contests: (_b = attributes.contests) !== null && _b !== void 0 ? _b : apple_utils_1.Rating.NONE,
25
+ gamblingSimulated: (_c = attributes.gamblingSimulated) !== null && _c !== void 0 ? _c : apple_utils_1.Rating.NONE,
26
+ horrorOrFearThemes: (_d = attributes.horrorOrFearThemes) !== null && _d !== void 0 ? _d : apple_utils_1.Rating.NONE,
27
+ matureOrSuggestiveThemes: (_e = attributes.matureOrSuggestiveThemes) !== null && _e !== void 0 ? _e : apple_utils_1.Rating.NONE,
28
+ medicalOrTreatmentInformation: (_f = attributes.medicalOrTreatmentInformation) !== null && _f !== void 0 ? _f : apple_utils_1.Rating.NONE,
29
+ profanityOrCrudeHumor: (_g = attributes.profanityOrCrudeHumor) !== null && _g !== void 0 ? _g : apple_utils_1.Rating.NONE,
30
+ sexualContentGraphicAndNudity: (_h = attributes.sexualContentGraphicAndNudity) !== null && _h !== void 0 ? _h : apple_utils_1.Rating.NONE,
31
+ sexualContentOrNudity: (_j = attributes.sexualContentOrNudity) !== null && _j !== void 0 ? _j : apple_utils_1.Rating.NONE,
32
+ violenceCartoonOrFantasy: (_k = attributes.violenceCartoonOrFantasy) !== null && _k !== void 0 ? _k : apple_utils_1.Rating.NONE,
33
+ violenceRealistic: (_l = attributes.violenceRealistic) !== null && _l !== void 0 ? _l : apple_utils_1.Rating.NONE,
34
+ violenceRealisticProlongedGraphicOrSadistic: (_m = attributes.violenceRealisticProlongedGraphicOrSadistic) !== null && _m !== void 0 ? _m : apple_utils_1.Rating.NONE,
35
+ gambling: (_o = attributes.gambling) !== null && _o !== void 0 ? _o : false,
36
+ unrestrictedWebAccess: (_p = attributes.unrestrictedWebAccess) !== null && _p !== void 0 ? _p : false,
37
+ kidsAgeBand: (_q = attributes.kidsAgeBand) !== null && _q !== void 0 ? _q : null,
38
+ seventeenPlus: (_r = attributes.seventeenPlus) !== null && _r !== void 0 ? _r : false,
39
+ };
22
40
  }
23
41
  setInfoLocale(attributes) {
24
42
  var _a, _b, _c;
@@ -26,21 +44,41 @@ class AppleConfigWriter {
26
44
  const existing = (_b = this.schema.info[attributes.locale]) !== null && _b !== void 0 ? _b : {};
27
45
  this.schema.info[attributes.locale] = {
28
46
  ...existing,
29
- title: (_c = attributes.name) !== null && _c !== void 0 ? _c : 'no name provided',
47
+ title: (_c = attributes.name) !== null && _c !== void 0 ? _c : '',
30
48
  subtitle: optional(attributes.subtitle),
31
49
  privacyPolicyUrl: optional(attributes.privacyPolicyUrl),
32
50
  privacyPolicyText: optional(attributes.privacyPolicyText),
33
51
  privacyChoicesUrl: optional(attributes.privacyChoicesUrl),
34
52
  };
35
53
  }
36
- setCategories({ primaryCategory, secondaryCategory }) {
54
+ setCategories(attributes) {
55
+ var _a, _b, _c, _d, _e, _f;
56
+ this.schema.categories = undefined;
57
+ if (!attributes.primaryCategory && !attributes.secondaryCategory) {
58
+ return;
59
+ }
37
60
  this.schema.categories = [];
38
- // TODO: see why these types are conflicting
39
- if (primaryCategory) {
40
- this.schema.categories.push(primaryCategory.id);
41
- if (secondaryCategory) {
42
- this.schema.categories.push(secondaryCategory.id);
43
- }
61
+ if (attributes.primaryCategory && attributes.primarySubcategoryOne) {
62
+ this.schema.categories[0] = [
63
+ attributes.primaryCategory.id,
64
+ (_a = attributes.primarySubcategoryOne) === null || _a === void 0 ? void 0 : _a.id,
65
+ (_b = attributes.primarySubcategoryTwo) === null || _b === void 0 ? void 0 : _b.id,
66
+ ].filter(Boolean);
67
+ }
68
+ else {
69
+ // If only the secondaryCategory was provided,
70
+ // autofill with an empty string and cause a store config error.
71
+ this.schema.categories[0] = (_d = (_c = attributes.primaryCategory) === null || _c === void 0 ? void 0 : _c.id) !== null && _d !== void 0 ? _d : '';
72
+ }
73
+ if (attributes.secondaryCategory && attributes.secondarySubcategoryOne) {
74
+ this.schema.categories[1] = [
75
+ attributes.secondaryCategory.id,
76
+ (_e = attributes.secondarySubcategoryOne) === null || _e === void 0 ? void 0 : _e.id,
77
+ (_f = attributes.secondarySubcategoryTwo) === null || _f === void 0 ? void 0 : _f.id,
78
+ ].filter(Boolean);
79
+ }
80
+ else if (attributes.secondaryCategory) {
81
+ this.schema.categories[1] = attributes.secondaryCategory.id;
44
82
  }
45
83
  }
46
84
  setVersion(attributes) {
@@ -58,9 +96,9 @@ class AppleConfigWriter {
58
96
  };
59
97
  }
60
98
  if (attributes.releaseType === apple_utils_1.ReleaseType.MANUAL) {
61
- this.schema.release = {
62
- automaticRelease: false,
63
- };
99
+ // ReleaseType.MANUAL is the default behavior, so we don't need to configure it.
100
+ // Setting `"automaticRelease": false` is a bit confusing for people who don't know what automaticRelease does.
101
+ this.schema.release = undefined;
64
102
  }
65
103
  }
66
104
  setVersionLocale(attributes) {
@@ -77,6 +115,20 @@ class AppleConfigWriter {
77
115
  supportUrl: optional(attributes.supportUrl),
78
116
  };
79
117
  }
118
+ setReviewDetails(attributes) {
119
+ var _a, _b, _c, _d;
120
+ this.schema.review = {
121
+ firstName: (_a = attributes.contactFirstName) !== null && _a !== void 0 ? _a : '',
122
+ lastName: (_b = attributes.contactLastName) !== null && _b !== void 0 ? _b : '',
123
+ email: (_c = attributes.contactEmail) !== null && _c !== void 0 ? _c : '',
124
+ phone: (_d = attributes.contactPhone) !== null && _d !== void 0 ? _d : '',
125
+ demoUsername: optional(attributes.demoAccountName),
126
+ demoPassword: optional(attributes.demoAccountPassword),
127
+ demoRequired: optional(attributes.demoAccountRequired),
128
+ notes: optional(attributes.notes),
129
+ // TODO: add attachment
130
+ };
131
+ }
80
132
  }
81
133
  exports.AppleConfigWriter = AppleConfigWriter;
82
134
  /** Helper function to convert `T | null` to `T | undefined`, required for the entity properties */
@@ -2,6 +2,7 @@
2
2
  import type { App } from '@expo/apple-utils';
3
3
  import type { AgeRatingData } from './tasks/age-rating';
4
4
  import type { AppInfoData } from './tasks/app-info';
5
+ import type { AppReviewData } from './tasks/app-review-detail';
5
6
  import type { AppVersionData } from './tasks/app-version';
6
7
  /**
7
8
  * The fully prepared apple data, used within the `downloadAsync` or `uploadAsync` tasks.
@@ -9,7 +10,7 @@ import type { AppVersionData } from './tasks/app-version';
9
10
  */
10
11
  export declare type AppleData = {
11
12
  app: App;
12
- } & AppInfoData & AppVersionData & AgeRatingData;
13
+ } & AppInfoData & AppVersionData & AgeRatingData & AppReviewData;
13
14
  /**
14
15
  * The unprepared partial apple data, used within the `prepareAsync` tasks.
15
16
  * It contains a reference to the app, each task should populate the necessary data.
@@ -0,0 +1,14 @@
1
+ /// <reference types="@expo/apple-utils/ts-declarations/expo__app-store" />
2
+ import { AppStoreReviewDetail } from '@expo/apple-utils';
3
+ import { AppleTask, TaskDownloadOptions, TaskPrepareOptions, TaskUploadOptions } from '../task';
4
+ export declare type AppReviewData = {
5
+ /** The current app info that should be edited */
6
+ reviewDetail: AppStoreReviewDetail;
7
+ };
8
+ /** Handle all contact, demo account, or instruction info that are required for the App Store review team. */
9
+ export declare class AppReviewDetailTask extends AppleTask {
10
+ name: () => string;
11
+ prepareAsync({ context }: TaskPrepareOptions): Promise<void>;
12
+ downloadAsync({ config, context }: TaskDownloadOptions): Promise<void>;
13
+ uploadAsync({ config, context }: TaskUploadOptions): Promise<void>;
14
+ }
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AppReviewDetailTask = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const assert_1 = tslib_1.__importDefault(require("assert"));
6
+ const chalk_1 = tslib_1.__importDefault(require("chalk"));
7
+ const log_1 = tslib_1.__importDefault(require("../../../log"));
8
+ const log_2 = require("../../utils/log");
9
+ const task_1 = require("../task");
10
+ /** Handle all contact, demo account, or instruction info that are required for the App Store review team. */
11
+ class AppReviewDetailTask extends task_1.AppleTask {
12
+ constructor() {
13
+ super(...arguments);
14
+ this.name = () => 'app review detail';
15
+ }
16
+ async prepareAsync({ context }) {
17
+ var _a;
18
+ (0, assert_1.default)(context.version, `App version not initialized, can't download store review details`);
19
+ context.reviewDetail = (_a = (await context.version.getAppStoreReviewDetailAsync())) !== null && _a !== void 0 ? _a : undefined;
20
+ }
21
+ async downloadAsync({ config, context }) {
22
+ if (context.reviewDetail) {
23
+ config.setReviewDetails(context.reviewDetail.attributes);
24
+ }
25
+ }
26
+ async uploadAsync({ config, context }) {
27
+ const reviewDetail = config.getReviewDetails();
28
+ if (!reviewDetail) {
29
+ return log_1.default.log((0, chalk_1.default) `{dim - Skipped store review details, not configured}`);
30
+ }
31
+ (0, assert_1.default)(context.version, `App version not initialized, can't upload store review details`);
32
+ const { versionString } = context.version.attributes;
33
+ if (!context.reviewDetail) {
34
+ // We can't set the demo required property when creating, omit it from the request
35
+ const { demoAccountRequired, ...reviewDetailsToCreate } = reviewDetail;
36
+ context.reviewDetail = await (0, log_2.logAsync)(() => context.version.createReviewDetailAsync(reviewDetailsToCreate), {
37
+ pending: `Creating store review details for ${chalk_1.default.bold(versionString)}...`,
38
+ success: `Created store review details for ${chalk_1.default.bold(versionString)}`,
39
+ failure: `Failed creating store review details for ${chalk_1.default.bold(versionString)}`,
40
+ });
41
+ }
42
+ context.reviewDetail = await (0, log_2.logAsync)(() => context.reviewDetail.updateAsync(reviewDetail), {
43
+ pending: `Updating store review details for ${chalk_1.default.bold(versionString)}...`,
44
+ success: `Updated store review details for ${chalk_1.default.bold(versionString)}`,
45
+ failure: `Failed updating store review details for ${chalk_1.default.bold(versionString)}`,
46
+ });
47
+ }
48
+ }
49
+ exports.AppReviewDetailTask = AppReviewDetailTask;
@@ -49,8 +49,8 @@ class AppVersionTask extends task_1.AppleTask {
49
49
  .join(' and ');
50
50
  context.version = await (0, log_2.logAsync)(() => context.version.updateAsync({ ...version, ...release }), {
51
51
  pending: `Updating ${description} info for ${chalk_1.default.bold(versionString)}...`,
52
- success: `Updated ${description} info for ${chalk_1.default.bold(versionString)}...`,
53
- failure: `Failed updating ${description} info for ${chalk_1.default.bold(versionString)}...`,
52
+ success: `Updated ${description} info for ${chalk_1.default.bold(versionString)}`,
53
+ failure: `Failed updating ${description} info for ${chalk_1.default.bold(versionString)}`,
54
54
  });
55
55
  }
56
56
  const locales = config.getLocales();
@@ -3,11 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createAppleTasks = void 0;
4
4
  const age_rating_1 = require("./age-rating");
5
5
  const app_info_1 = require("./app-info");
6
+ const app_review_detail_1 = require("./app-review-detail");
6
7
  const app_version_1 = require("./app-version");
7
8
  /**
8
9
  * List of all eligible tasks to sync local store configuration to the App store.
9
10
  */
10
11
  function createAppleTasks(_ctx) {
11
- return [new app_version_1.AppVersionTask(), new app_info_1.AppInfoTask(), new age_rating_1.AgeRatingTask()];
12
+ return [new app_version_1.AppVersionTask(), new app_info_1.AppInfoTask(), new age_rating_1.AgeRatingTask(), new app_review_detail_1.AppReviewDetailTask()];
12
13
  }
13
14
  exports.createAppleTasks = createAppleTasks;
@@ -1,20 +1,18 @@
1
1
  /// <reference types="@expo/apple-utils/ts-declarations/expo__app-store" />
2
- import type { AgeRatingDeclarationProps, AppCategoryId, AppSubcategoryId } from '@expo/apple-utils';
2
+ import type { AgeRatingDeclarationProps } from '@expo/apple-utils';
3
3
  export declare type AppleLocale = string;
4
4
  export interface AppleMetadata {
5
5
  copyright?: string;
6
6
  info?: Record<AppleLocale, AppleInfo>;
7
- categories?: AppCategoryId[] | AppleCategory;
7
+ categories?: AppleCategory;
8
8
  release?: AppleRelease;
9
9
  advisory?: AppleAdvisory;
10
10
  preview?: Record<string, string[]>;
11
11
  review?: AppleReview;
12
12
  }
13
13
  export declare type AppleAdvisory = Partial<AgeRatingDeclarationProps>;
14
- export interface AppleCategory {
15
- category: AppCategoryId;
16
- subcategory?: AppSubcategoryId[];
17
- }
14
+ /** Apps can define up to two categories, or categories with up to two subcategories */
15
+ export declare type AppleCategory = (string | string[])[];
18
16
  export interface AppleRelease {
19
17
  isPhasedReleaseEnabled?: boolean;
20
18
  shouldResetRatings?: boolean;
@@ -39,12 +37,12 @@ export interface AppleInfo {
39
37
  supportUrl?: string;
40
38
  }
41
39
  export interface AppleReview {
42
- firstName?: string;
43
- lastName?: string;
44
- phone?: string;
45
- email?: string;
40
+ firstName: string;
41
+ lastName: string;
42
+ phone: string;
43
+ email: string;
46
44
  demoUsername?: string;
47
45
  demoPassword?: string;
46
+ demoRequired?: boolean;
48
47
  notes?: string;
49
- attachment?: string;
50
48
  }
@@ -30,6 +30,11 @@ export declare class MetadataDownloadError extends Error {
30
30
  readonly executionId: string;
31
31
  constructor(errors: Error[], executionId: string);
32
32
  }
33
+ /**
34
+ * Log the encountered metadata validation error in detail for the user.
35
+ * This should help communicate any possible configuration error and help the user resolve it.
36
+ */
37
+ export declare function logMetadataValidationError(error: MetadataValidationError): void;
33
38
  /**
34
39
  * Handle a thrown metadata error by informing the user what went wrong.
35
40
  * If a normal error is thrown, this method will re-throw that error to avoid consuming it.
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.handleMetadataError = exports.MetadataDownloadError = exports.MetadataUploadError = exports.MetadataValidationError = void 0;
3
+ exports.handleMetadataError = exports.logMetadataValidationError = exports.MetadataDownloadError = exports.MetadataUploadError = exports.MetadataValidationError = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const chalk_1 = tslib_1.__importDefault(require("chalk"));
6
6
  const log_1 = tslib_1.__importStar(require("../log"));
@@ -44,24 +44,33 @@ class MetadataDownloadError extends Error {
44
44
  }
45
45
  }
46
46
  exports.MetadataDownloadError = MetadataDownloadError;
47
+ /**
48
+ * Log the encountered metadata validation error in detail for the user.
49
+ * This should help communicate any possible configuration error and help the user resolve it.
50
+ */
51
+ function logMetadataValidationError(error) {
52
+ var _a;
53
+ log_1.default.newLine();
54
+ log_1.default.error(chalk_1.default.bold(error.message));
55
+ if (((_a = error.errors) === null || _a === void 0 ? void 0 : _a.length) > 0) {
56
+ // TODO(cedric): group errors by property to make multiple errors for same property more readable
57
+ log_1.default.log(error.errors.map(err => ` - ${chalk_1.default.bold(err.dataPath)} ${err.message}`).join('\n'));
58
+ }
59
+ }
60
+ exports.logMetadataValidationError = logMetadataValidationError;
47
61
  /**
48
62
  * Handle a thrown metadata error by informing the user what went wrong.
49
63
  * If a normal error is thrown, this method will re-throw that error to avoid consuming it.
50
64
  */
51
65
  function handleMetadataError(error) {
52
- var _a, _b;
66
+ var _a;
53
67
  if (error instanceof MetadataValidationError) {
54
- log_1.default.newLine();
55
- log_1.default.error(chalk_1.default.bold(error.message));
56
- if (((_a = error.errors) === null || _a === void 0 ? void 0 : _a.length) > 0) {
57
- log_1.default.log(error.errors.map(err => ` - ${err.dataPath} ${err.message}`).join('\n'));
58
- }
59
- return;
68
+ return logMetadataValidationError(error);
60
69
  }
61
70
  if (error instanceof MetadataDownloadError || error instanceof MetadataUploadError) {
62
71
  log_1.default.newLine();
63
72
  log_1.default.error(chalk_1.default.bold(error.message));
64
- if (((_b = error.errors) === null || _b === void 0 ? void 0 : _b.length) > 0) {
73
+ if (((_a = error.errors) === null || _a === void 0 ? void 0 : _a.length) > 0) {
65
74
  log_1.default.newLine();
66
75
  log_1.default.error(error.errors.map(err => err.message).join('\n\n'));
67
76
  }
@@ -6,6 +6,7 @@ const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
6
6
  const path_1 = tslib_1.__importDefault(require("path"));
7
7
  const events_1 = require("../analytics/events");
8
8
  const log_1 = tslib_1.__importDefault(require("../log"));
9
+ const prompts_1 = require("../prompts");
9
10
  const tasks_1 = require("./apple/tasks");
10
11
  const config_1 = require("./config");
11
12
  const context_1 = require("./context");
@@ -20,13 +21,22 @@ async function uploadMetadataAsync(metadataCtx) {
20
21
  if (!(await fs_extra_1.default.pathExists(filePath))) {
21
22
  throw new errors_1.MetadataValidationError(`Store configuration file not found "${filePath}"`);
22
23
  }
23
- const { app, auth } = await (0, context_1.ensureMetadataAppStoreAuthenticatedAsync)(metadataCtx);
24
- const { unsubscribeTelemetry, executionId } = (0, telemetry_1.subscribeTelemetry)(events_1.MetadataEvent.APPLE_METADATA_UPLOAD, { app, auth });
25
24
  const fileData = await fs_extra_1.default.readJson(filePath);
26
25
  const { valid, errors: validationErrors } = (0, config_1.validateConfig)(fileData);
27
26
  if (!valid) {
28
- throw new errors_1.MetadataValidationError(`Store configuration errors found`, validationErrors);
27
+ const error = new errors_1.MetadataValidationError(`Store configuration errors found`, validationErrors);
28
+ (0, errors_1.logMetadataValidationError)(error);
29
+ log_1.default.newLine();
30
+ 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.');
31
+ const attempt = await (0, prompts_1.confirmAsync)({
32
+ message: 'Do you still want to push the store configuration?',
33
+ });
34
+ if (!attempt) {
35
+ throw error;
36
+ }
29
37
  }
38
+ const { app, auth } = await (0, context_1.ensureMetadataAppStoreAuthenticatedAsync)(metadataCtx);
39
+ const { unsubscribeTelemetry, executionId } = (0, telemetry_1.subscribeTelemetry)(events_1.MetadataEvent.APPLE_METADATA_UPLOAD, { app, auth });
30
40
  log_1.default.addNewLineIfNone();
31
41
  log_1.default.log('Uploading App Store configuration...');
32
42
  const errors = [];
@@ -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];
@@ -10,6 +10,7 @@ const chalk_1 = tslib_1.__importDefault(require("chalk"));
10
10
  const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
11
11
  const nullthrows_1 = tslib_1.__importDefault(require("nullthrows"));
12
12
  const appJson_1 = require("../../build/utils/appJson");
13
+ const env_1 = tslib_1.__importDefault(require("../../env"));
13
14
  const log_1 = tslib_1.__importStar(require("../../log"));
14
15
  const projectUtils_1 = require("../../project/projectUtils");
15
16
  const prompts_1 = require("../../prompts");
@@ -37,6 +38,9 @@ class AmbiguousApplicationIdError extends Error {
37
38
  }
38
39
  exports.AmbiguousApplicationIdError = AmbiguousApplicationIdError;
39
40
  async function getApplicationIdFromBareAsync(projectDir, gradleContext) {
41
+ if (env_1.default.overrideAndroidApplicationId) {
42
+ return env_1.default.overrideAndroidApplicationId;
43
+ }
40
44
  const errorMessage = 'Could not read applicationId from Android project.';
41
45
  if (gradleContext) {
42
46
  const buildGradle = await gradleUtils.getAppBuildGradleAsync(projectDir);
@@ -116,8 +120,8 @@ exports.isApplicationIdValid = isApplicationIdValid;
116
120
  let warnPrinted = false;
117
121
  function warnIfAndroidPackageDefinedInAppConfigForBareWorkflowProject(projectDir, exp) {
118
122
  if (config_plugins_1.AndroidConfig.Package.getPackage(exp) && !warnPrinted) {
119
- log_1.default.warn(`Specifying "android.package" in ${(0, projectUtils_1.getProjectConfigDescription)(projectDir)} is deprecated for bare workflow projects.\n` +
120
- '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.');
121
125
  warnPrinted = true;
122
126
  }
123
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;