eas-cli 3.6.1 → 3.7.1

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.
@@ -6,6 +6,7 @@ const eas_build_job_1 = require("@expo/eas-build-job");
6
6
  const nullthrows_1 = tslib_1.__importDefault(require("nullthrows"));
7
7
  const path_1 = tslib_1.__importDefault(require("path"));
8
8
  const slash_1 = tslib_1.__importDefault(require("slash"));
9
+ const customBuildConfig_1 = require("../../project/customBuildConfig");
9
10
  const projectUtils_1 = require("../../project/projectUtils");
10
11
  const vcs_1 = require("../../vcs");
11
12
  const cacheDefaults = {
@@ -15,8 +16,9 @@ const cacheDefaults = {
15
16
  };
16
17
  async function prepareJobAsync(ctx, jobData) {
17
18
  var _a;
18
- const projectRootDirectory = (0, slash_1.default)(path_1.default.relative(await (0, vcs_1.getVcsClient)().getRootPathAsync(), ctx.projectDir)) || '.';
19
19
  const username = (0, projectUtils_1.getUsername)(ctx.exp, ctx.user);
20
+ const buildProfile = ctx.buildProfile;
21
+ const projectRootDirectory = (0, slash_1.default)(path_1.default.relative(await (0, vcs_1.getVcsClient)().getRootPathAsync(), ctx.projectDir)) || '.';
20
22
  const buildCredentials = {};
21
23
  if (jobData.credentials) {
22
24
  const targetNames = Object.keys(jobData.credentials);
@@ -24,37 +26,40 @@ async function prepareJobAsync(ctx, jobData) {
24
26
  buildCredentials[targetName] = prepareTargetCredentials(jobData.credentials[targetName]);
25
27
  }
26
28
  }
29
+ const maybeCustomBuildConfigPath = buildProfile.config
30
+ ? (0, customBuildConfig_1.getCustomBuildConfigPath)(buildProfile.config)
31
+ : undefined;
27
32
  const job = {
28
33
  type: ctx.workflow,
29
34
  platform: eas_build_job_1.Platform.IOS,
30
35
  projectArchive: jobData.projectArchive,
31
36
  projectRootDirectory,
32
37
  builderEnvironment: {
33
- image: ctx.buildProfile.image,
34
- node: ctx.buildProfile.node,
35
- yarn: ctx.buildProfile.yarn,
36
- bundler: ctx.buildProfile.bundler,
37
- cocoapods: ctx.buildProfile.cocoapods,
38
- fastlane: ctx.buildProfile.fastlane,
39
- expoCli: ctx.buildProfile.expoCli,
40
- env: ctx.buildProfile.env,
38
+ image: buildProfile.image,
39
+ node: buildProfile.node,
40
+ yarn: buildProfile.yarn,
41
+ bundler: buildProfile.bundler,
42
+ cocoapods: buildProfile.cocoapods,
43
+ fastlane: buildProfile.fastlane,
44
+ expoCli: buildProfile.expoCli,
45
+ env: buildProfile.env,
41
46
  },
42
47
  cache: {
43
48
  ...cacheDefaults,
44
- ...ctx.buildProfile.cache,
49
+ ...buildProfile.cache,
45
50
  clear: ctx.clearCache,
46
51
  },
47
52
  secrets: {
48
53
  buildCredentials,
49
54
  },
50
- releaseChannel: ctx.buildProfile.releaseChannel,
51
- updates: { channel: ctx.buildProfile.channel },
52
- developmentClient: ctx.buildProfile.developmentClient,
53
- simulator: ctx.buildProfile.simulator,
55
+ releaseChannel: buildProfile.releaseChannel,
56
+ updates: { channel: buildProfile.channel },
57
+ developmentClient: buildProfile.developmentClient,
58
+ simulator: buildProfile.simulator,
54
59
  scheme: jobData.buildScheme,
55
- buildConfiguration: ctx.buildProfile.buildConfiguration,
56
- applicationArchivePath: (_a = ctx.buildProfile.applicationArchivePath) !== null && _a !== void 0 ? _a : ctx.buildProfile.artifactPath,
57
- buildArtifactPaths: ctx.buildProfile.buildArtifactPaths,
60
+ buildConfiguration: buildProfile.buildConfiguration,
61
+ applicationArchivePath: (_a = buildProfile.applicationArchivePath) !== null && _a !== void 0 ? _a : buildProfile.artifactPath,
62
+ buildArtifactPaths: buildProfile.buildArtifactPaths,
58
63
  username,
59
64
  ...(ctx.ios.buildNumberOverride && {
60
65
  version: {
@@ -62,10 +67,15 @@ async function prepareJobAsync(ctx, jobData) {
62
67
  },
63
68
  }),
64
69
  experimental: {
65
- prebuildCommand: ctx.buildProfile.prebuildCommand,
70
+ prebuildCommand: buildProfile.prebuildCommand,
66
71
  },
67
- mode: eas_build_job_1.BuildMode.BUILD,
72
+ mode: buildProfile.config ? eas_build_job_1.BuildMode.CUSTOM : eas_build_job_1.BuildMode.BUILD,
68
73
  triggeredBy: eas_build_job_1.BuildTrigger.EAS_CLI,
74
+ ...(maybeCustomBuildConfigPath && {
75
+ customBuildConfig: {
76
+ path: maybeCustomBuildConfigPath,
77
+ },
78
+ }),
69
79
  };
70
80
  return (0, eas_build_job_1.sanitizeJob)(job);
71
81
  }
@@ -45,6 +45,7 @@ async function collectMetadataAsync(ctx) {
45
45
  }),
46
46
  runWithNoWaitFlag: ctx.noWait,
47
47
  runFromCI: ctx.runFromCI,
48
+ buildMode: ctx.buildProfile.config ? eas_build_job_1.BuildMode.CUSTOM : eas_build_job_1.BuildMode.BUILD,
48
49
  };
49
50
  return (0, eas_build_job_1.sanitizeMetadata)(metadata);
50
51
  }
@@ -12,6 +12,7 @@ const BuildQuery_1 = require("../graphql/queries/BuildQuery");
12
12
  const AppPlatform_1 = require("../graphql/types/AppPlatform");
13
13
  const log_1 = tslib_1.__importDefault(require("../log"));
14
14
  const platform_1 = require("../platform");
15
+ const customBuildConfig_1 = require("../project/customBuildConfig");
15
16
  const expoSdk_1 = require("../project/expoSdk");
16
17
  const metroConfig_1 = require("../project/metroConfig");
17
18
  const projectUtils_1 = require("../project/projectUtils");
@@ -62,6 +63,7 @@ async function runBuildAndSubmitAsync(graphqlClient, analytics, projectDir, flag
62
63
  });
63
64
  for (const buildProfile of buildProfiles) {
64
65
  (0, remoteVersionSource_1.validateBuildProfileVersionSettings)(buildProfile, easJsonCliConfig);
66
+ await (0, customBuildConfig_1.validateCustomBuildConfigAsync)(projectDir, buildProfile.profile);
65
67
  }
66
68
  const startedBuilds = [];
67
69
  const buildCtxByPlatform = {};
@@ -38,7 +38,6 @@ function printLogsUrls(builds) {
38
38
  }
39
39
  exports.printLogsUrls = printLogsUrls;
40
40
  function printBuildResults(builds) {
41
- log_1.default.newLine();
42
41
  if (builds.length === 1) {
43
42
  const [build] = builds;
44
43
  (0, assert_1.default)(build, 'Build should be defined');
@@ -50,9 +49,9 @@ function printBuildResults(builds) {
50
49
  }
51
50
  exports.printBuildResults = printBuildResults;
52
51
  function printBuildResult(build) {
53
- var _a, _b;
54
- log_1.default.addNewLineIfNone();
52
+ var _a;
55
53
  if (build.status === generated_1.BuildStatus.Errored) {
54
+ log_1.default.addNewLineIfNone();
56
55
  const userError = build.error;
57
56
  log_1.default.error(`${platform_1.appPlatformEmojis[build.platform]} ${platform_1.appPlatformDisplayNames[build.platform]} build failed${userError ? ':' : ''}`);
58
57
  if (userError) {
@@ -61,10 +60,12 @@ function printBuildResult(build) {
61
60
  return;
62
61
  }
63
62
  if (build.status === generated_1.BuildStatus.Canceled) {
63
+ log_1.default.addNewLineIfNone();
64
64
  log_1.default.error(`${platform_1.appPlatformEmojis[build.platform]} ${platform_1.appPlatformDisplayNames[build.platform]} build was canceled`);
65
65
  return;
66
66
  }
67
67
  if (build.distribution === generated_1.DistributionType.Internal) {
68
+ log_1.default.addNewLineIfNone();
68
69
  const logsUrl = (0, url_1.getBuildLogsUrl)(build);
69
70
  // It's tricky to install the .apk file directly on Android so let's fallback
70
71
  // to the build details page and let people press the button to download there
@@ -76,9 +77,12 @@ function printBuildResult(build) {
76
77
  else {
77
78
  // TODO: it looks like buildUrl could possibly be undefined, based on the code below.
78
79
  // we should account for this case better if it is possible
79
- const url = (_b = (_a = build.artifacts) === null || _a === void 0 ? void 0 : _a.buildUrl) !== null && _b !== void 0 ? _b : '';
80
- log_1.default.log(`${platform_1.appPlatformEmojis[build.platform]} ${platform_1.appPlatformDisplayNames[build.platform]} app:`);
81
- log_1.default.log(`${(0, log_1.link)(url)}`);
80
+ const url = (_a = build.artifacts) === null || _a === void 0 ? void 0 : _a.buildUrl;
81
+ if (url) {
82
+ log_1.default.addNewLineIfNone();
83
+ log_1.default.log(`${platform_1.appPlatformEmojis[build.platform]} ${platform_1.appPlatformDisplayNames[build.platform]} app:`);
84
+ log_1.default.log((0, log_1.link)(url));
85
+ }
82
86
  }
83
87
  }
84
88
  function printDeprecationWarnings(deprecationInfo) {
@@ -164,10 +164,27 @@ class UpdatePublish extends EasCommand_1.default {
164
164
  uploadedAssetCount = uploadResults.uniqueUploadedAssetCount;
165
165
  assetLimitPerUpdateGroup = uploadResults.assetLimitPerUpdateGroup;
166
166
  unsortedUpdateInfoGroups = await (0, publish_1.buildUnsortedUpdateInfoGroupAsync)(assets, exp);
167
- const uploadAssetSuccessMessage = uploadedAssetCount
168
- ? `Uploaded ${uploadedAssetCount} ${uploadedAssetCount === 1 ? 'platform' : 'platforms'}`
169
- : `Uploaded: No changes detected`;
170
- assetSpinner.succeed(uploadAssetSuccessMessage);
167
+ // NOTE(cedric): we assume that bundles are always uploaded, and always are part of
168
+ // `uploadedAssetCount`, perferably we don't assume. For that, we need to refactor the
169
+ // `uploadAssetsAsync` and be able to determine asset type from the uploaded assets.
170
+ const uploadedBundleCount = uploadResults.launchAssetCount;
171
+ const uploadedNormalAssetCount = Math.max(0, uploadedAssetCount - uploadedBundleCount);
172
+ const reusedNormalAssetCount = uploadResults.uniqueAssetCount - uploadedNormalAssetCount;
173
+ assetSpinner.stop();
174
+ log_1.default.withTick(`Uploaded ${uploadedBundleCount} app ${uploadedBundleCount === 1 ? 'bundle' : 'bundles'}`);
175
+ if (uploadedNormalAssetCount === 0) {
176
+ log_1.default.withTick(`Uploading assets skipped - no new assets found`);
177
+ }
178
+ else {
179
+ let message = `Uploaded ${uploadedNormalAssetCount} ${uploadedNormalAssetCount === 1 ? 'asset' : 'assets'}`;
180
+ if (reusedNormalAssetCount > 0) {
181
+ message += ` (reused ${reusedNormalAssetCount} ${reusedNormalAssetCount === 1 ? 'asset' : 'assets'})`;
182
+ }
183
+ log_1.default.withTick(message);
184
+ }
185
+ for (const uploadedAssetPath of uploadResults.uniqueUploadedAssetPaths) {
186
+ log_1.default.debug(chalk_1.default.dim(`- ${uploadedAssetPath}`));
187
+ }
171
188
  }
172
189
  catch (e) {
173
190
  assetSpinner.fail('Failed to upload');
@@ -123,11 +123,15 @@ export type Account = {
123
123
  subscription?: Maybe<SubscriptionDetails>;
124
124
  /** @deprecated No longer needed */
125
125
  subscriptionChangesPending?: Maybe<Scalars['Boolean']>;
126
+ /** Coalesced project activity for an app using pagination */
127
+ timelineActivity: TimelineActivityConnection;
126
128
  /** @deprecated See isCurrent */
127
129
  unlimitedBuilds: Scalars['Boolean'];
128
130
  updatedAt: Scalars['DateTime'];
129
131
  /** Account query object for querying EAS usage metrics */
130
132
  usageMetrics: AccountUsageMetrics;
133
+ /** Owning UserActor of this account if personal account */
134
+ userActorOwner?: Maybe<UserActor>;
131
135
  /** Pending user invitations for this account */
132
136
  userInvitations: Array<UserInvitation>;
133
137
  /** Actors associated with this account and permissions they hold */
@@ -234,6 +238,17 @@ export type AccountSnacksArgs = {
234
238
  limit: Scalars['Int'];
235
239
  offset: Scalars['Int'];
236
240
  };
241
+ /**
242
+ * An account is a container owning projects, credentials, billing and other organization
243
+ * data and settings. Actors may own and be members of accounts.
244
+ */
245
+ export type AccountTimelineActivityArgs = {
246
+ after?: InputMaybe<Scalars['String']>;
247
+ before?: InputMaybe<Scalars['String']>;
248
+ filter?: InputMaybe<TimelineActivityFilterInput>;
249
+ first?: InputMaybe<Scalars['Int']>;
250
+ last?: InputMaybe<Scalars['Int']>;
251
+ };
237
252
  export type AccountDataInput = {
238
253
  name: Scalars['String'];
239
254
  };
@@ -666,6 +681,7 @@ export type AndroidJobInput = {
666
681
  buildType?: InputMaybe<AndroidBuildType>;
667
682
  builderEnvironment?: InputMaybe<AndroidBuilderEnvironmentInput>;
668
683
  cache?: InputMaybe<BuildCacheInput>;
684
+ customBuildConfig?: InputMaybe<CustomBuildConfigInput>;
669
685
  developmentClient?: InputMaybe<Scalars['Boolean']>;
670
686
  experimental?: InputMaybe<Scalars['JSONObject']>;
671
687
  gradleCommand?: InputMaybe<Scalars['String']>;
@@ -794,10 +810,8 @@ export type App = Project & {
794
810
  /** Classic update release channel names that have at least one build */
795
811
  buildsReleaseChannels: Array<Scalars['String']>;
796
812
  deployment?: Maybe<Deployment>;
797
- deploymentNew?: Maybe<DeploymentNew>;
798
813
  /** Deployments associated with this app */
799
- deployments: Array<Deployment>;
800
- deploymentsNew: DeploymentsConnection;
814
+ deployments: DeploymentsConnection;
801
815
  description: Scalars['String'];
802
816
  /** Environment secrets for an app */
803
817
  environmentSecrets: Array<EnvironmentSecret>;
@@ -909,23 +923,11 @@ export type AppBuildsArgs = {
909
923
  };
910
924
  /** Represents an Exponent App (or Experience in legacy terms) */
911
925
  export type AppDeploymentArgs = {
912
- channel: Scalars['String'];
913
- options?: InputMaybe<DeploymentOptions>;
914
- runtimeVersion: Scalars['String'];
915
- };
916
- /** Represents an Exponent App (or Experience in legacy terms) */
917
- export type AppDeploymentNewArgs = {
918
926
  channel: Scalars['String'];
919
927
  runtimeVersion: Scalars['String'];
920
928
  };
921
929
  /** Represents an Exponent App (or Experience in legacy terms) */
922
930
  export type AppDeploymentsArgs = {
923
- limit: Scalars['Int'];
924
- mostRecentlyUpdatedAt?: InputMaybe<Scalars['DateTime']>;
925
- options?: InputMaybe<DeploymentOptions>;
926
- };
927
- /** Represents an Exponent App (or Experience in legacy terms) */
928
- export type AppDeploymentsNewArgs = {
929
931
  after?: InputMaybe<Scalars['String']>;
930
932
  before?: InputMaybe<Scalars['String']>;
931
933
  first?: InputMaybe<Scalars['Int']>;
@@ -1606,6 +1608,7 @@ export declare enum BuildIosEnterpriseProvisioning {
1606
1608
  /** Represents an Standalone App build job */
1607
1609
  export type BuildJob = ActivityTimelineProjectActivity & BuildOrBuildJob & {
1608
1610
  __typename?: 'BuildJob';
1611
+ accountUserActor?: Maybe<UserActor>;
1609
1612
  activityTimestamp: Scalars['DateTime'];
1610
1613
  actor?: Maybe<Actor>;
1611
1614
  app?: Maybe<App>;
@@ -1701,6 +1704,7 @@ export type BuildMetrics = {
1701
1704
  };
1702
1705
  export declare enum BuildMode {
1703
1706
  Build = "BUILD",
1707
+ Custom = "CUSTOM",
1704
1708
  Resign = "RESIGN"
1705
1709
  }
1706
1710
  export type BuildMutation = {
@@ -1846,6 +1850,8 @@ export declare enum BuildResourceClass {
1846
1850
  IosLarge = "IOS_LARGE",
1847
1851
  IosM1Large = "IOS_M1_LARGE",
1848
1852
  IosM1Medium = "IOS_M1_MEDIUM",
1853
+ IosM2Medium = "IOS_M2_MEDIUM",
1854
+ IosM2ProMedium = "IOS_M2_PRO_MEDIUM",
1849
1855
  IosMedium = "IOS_MEDIUM",
1850
1856
  Legacy = "LEGACY"
1851
1857
  }
@@ -1981,6 +1987,9 @@ export type CreateSubmissionResult = {
1981
1987
  /** Created submission */
1982
1988
  submission: Submission;
1983
1989
  };
1990
+ export type CustomBuildConfigInput = {
1991
+ path: Scalars['String'];
1992
+ };
1984
1993
  export type DeleteAccessTokenResult = {
1985
1994
  __typename?: 'DeleteAccessTokenResult';
1986
1995
  id: Scalars['ID'];
@@ -2052,16 +2061,17 @@ export type DeployServerlessFunctionResult = {
2052
2061
  /** Represents a Deployment - a set of Builds with the same Runtime Version and Channel */
2053
2062
  export type Deployment = {
2054
2063
  __typename?: 'Deployment';
2055
- channel?: Maybe<UpdateChannel>;
2056
- /**
2057
- * The name of this deployment's associated channel. It is specified separately from the `channel`
2058
- * field to allow specifying a deployment before an EAS Update channel has been created.
2059
- */
2060
- channelName: Scalars['String'];
2064
+ builds: DeploymentBuildsConnection;
2065
+ channel: UpdateChannel;
2061
2066
  id: Scalars['ID'];
2062
- mostRecentlyUpdatedAt: Scalars['DateTime'];
2063
- recentBuilds: Array<Build>;
2064
- runtimeVersion: Scalars['String'];
2067
+ runtime: Runtime;
2068
+ };
2069
+ /** Represents a Deployment - a set of Builds with the same Runtime Version and Channel */
2070
+ export type DeploymentBuildsArgs = {
2071
+ after?: InputMaybe<Scalars['String']>;
2072
+ before?: InputMaybe<Scalars['String']>;
2073
+ first?: InputMaybe<Scalars['Int']>;
2074
+ last?: InputMaybe<Scalars['Int']>;
2065
2075
  };
2066
2076
  export type DeploymentBuildEdge = {
2067
2077
  __typename?: 'DeploymentBuildEdge';
@@ -2077,28 +2087,9 @@ export type DeploymentBuildsConnection = {
2077
2087
  export type DeploymentEdge = {
2078
2088
  __typename?: 'DeploymentEdge';
2079
2089
  cursor: Scalars['String'];
2080
- node: DeploymentNew;
2081
- };
2082
- /** Represents a Deployment - a set of Builds with the same Runtime Version and Channel */
2083
- export type DeploymentNew = {
2084
- __typename?: 'DeploymentNew';
2085
- builds: DeploymentBuildsConnection;
2086
- channel: UpdateChannel;
2087
- id: Scalars['ID'];
2088
- runtime: Runtime;
2089
- };
2090
- /** Represents a Deployment - a set of Builds with the same Runtime Version and Channel */
2091
- export type DeploymentNewBuildsArgs = {
2092
- after?: InputMaybe<Scalars['String']>;
2093
- before?: InputMaybe<Scalars['String']>;
2094
- first?: InputMaybe<Scalars['Int']>;
2095
- last?: InputMaybe<Scalars['Int']>;
2096
- };
2097
- export type DeploymentOptions = {
2098
- /** Max number of associated builds to return */
2099
- buildListMaxSize?: InputMaybe<Scalars['Int']>;
2090
+ node: Deployment;
2100
2091
  };
2101
- /** Represents the connection over the deploymentsNew edge of an App */
2092
+ /** Represents the connection over the deployments edge of an App */
2102
2093
  export type DeploymentsConnection = {
2103
2094
  __typename?: 'DeploymentsConnection';
2104
2095
  edges: Array<DeploymentEdge>;
@@ -2604,6 +2595,7 @@ export type IosJobInput = {
2604
2595
  buildType?: InputMaybe<IosBuildType>;
2605
2596
  builderEnvironment?: InputMaybe<IosBuilderEnvironmentInput>;
2606
2597
  cache?: InputMaybe<BuildCacheInput>;
2598
+ customBuildConfig?: InputMaybe<CustomBuildConfigInput>;
2607
2599
  developmentClient?: InputMaybe<Scalars['Boolean']>;
2608
2600
  /** @deprecated */
2609
2601
  distribution?: InputMaybe<DistributionType>;
@@ -118,6 +118,7 @@ var BuildJobStatus;
118
118
  var BuildMode;
119
119
  (function (BuildMode) {
120
120
  BuildMode["Build"] = "BUILD";
121
+ BuildMode["Custom"] = "CUSTOM";
121
122
  BuildMode["Resign"] = "RESIGN";
122
123
  })(BuildMode = exports.BuildMode || (exports.BuildMode = {}));
123
124
  var BuildPriority;
@@ -137,6 +138,8 @@ var BuildResourceClass;
137
138
  BuildResourceClass["IosLarge"] = "IOS_LARGE";
138
139
  BuildResourceClass["IosM1Large"] = "IOS_M1_LARGE";
139
140
  BuildResourceClass["IosM1Medium"] = "IOS_M1_MEDIUM";
141
+ BuildResourceClass["IosM2Medium"] = "IOS_M2_MEDIUM";
142
+ BuildResourceClass["IosM2ProMedium"] = "IOS_M2_PRO_MEDIUM";
140
143
  BuildResourceClass["IosMedium"] = "IOS_MEDIUM";
141
144
  BuildResourceClass["Legacy"] = "LEGACY";
142
145
  })(BuildResourceClass = exports.BuildResourceClass || (exports.BuildResourceClass = {}));
@@ -43,7 +43,7 @@ function parseGradleCommand(cmd, buildGradle) {
43
43
  // separate moduleName and rest of the definition
44
44
  const splitCmd = rawCmd.split(':');
45
45
  const [moduleName, taskName] = splitCmd.length > 1 ? [splitCmd[0], splitCmd[1]] : [undefined, splitCmd[0]];
46
- const matchResult = taskName.match(/(build|bundle|assemble)(.*)(Release|Debug)/);
46
+ const matchResult = taskName.match(/(build|bundle|assemble|package)(.*)(Release|Debug)/);
47
47
  if (!matchResult) {
48
48
  throw new Error(`Failed to parse gradle command: ${cmd}`);
49
49
  }
@@ -0,0 +1,4 @@
1
+ import { Platform } from '@expo/eas-build-job';
2
+ import { BuildProfile } from '@expo/eas-json';
3
+ export declare function validateCustomBuildConfigAsync(projectDir: string, profile: BuildProfile<Platform>): Promise<void>;
4
+ export declare function getCustomBuildConfigPath(configFilename: string): string;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getCustomBuildConfigPath = exports.validateCustomBuildConfigAsync = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const chalk_1 = tslib_1.__importDefault(require("chalk"));
6
+ const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
7
+ const path_1 = tslib_1.__importDefault(require("path"));
8
+ async function validateCustomBuildConfigAsync(projectDir, profile) {
9
+ if (!profile.config) {
10
+ return;
11
+ }
12
+ const relativeBuildConfigPath = getCustomBuildConfigPath(profile.config);
13
+ const buildConfigPath = path_1.default.join(projectDir, relativeBuildConfigPath);
14
+ if (!(await fs_extra_1.default.pathExists(buildConfigPath))) {
15
+ throw new Error(`Custom build configuration file ${chalk_1.default.bold(relativeBuildConfigPath)} does not exist.`);
16
+ }
17
+ }
18
+ exports.validateCustomBuildConfigAsync = validateCustomBuildConfigAsync;
19
+ function getCustomBuildConfigPath(configFilename) {
20
+ return path_1.default.join('.eas/build', configFilename);
21
+ }
22
+ exports.getCustomBuildConfigPath = getCustomBuildConfigPath;
@@ -21,6 +21,8 @@ export type RawAsset = {
21
21
  fileExtension?: string;
22
22
  contentType: string;
23
23
  path: string;
24
+ /** Original asset path derrived from asset map, or exported folder */
25
+ originalPath?: string;
24
26
  };
25
27
  type CollectedAssets = {
26
28
  [platform in Platform]?: {
@@ -42,6 +44,11 @@ type ManifestFragment = {
42
44
  type UpdateInfoGroup = {
43
45
  [key in Platform]: ManifestFragment;
44
46
  };
47
+ type AssetMap = Record<string, {
48
+ httpServerLocation: string;
49
+ name: string;
50
+ type: string;
51
+ }>;
45
52
  export declare const MetadataJoi: Joi.ObjectSchema<any>;
46
53
  export declare function guessContentTypeFromExtension(ext?: string): string;
47
54
  export declare function getBase64URLEncoding(buffer: Buffer): string;
@@ -69,6 +76,13 @@ export declare function resolveInputDirectoryAsync(inputDir: string, { skipBundl
69
76
  }): Promise<string>;
70
77
  export declare function loadMetadata(distRoot: string): Metadata;
71
78
  export declare function filterExportedPlatformsByFlag<T extends Partial<Record<Platform, any>>>(record: T, platformFlag: ExpoCLIExportPlatformFlag): T;
79
+ /** Try to load the asset map for logging the names of assets published */
80
+ export declare function loadAssetMapAsync(distRoot: string): Promise<AssetMap | null>;
81
+ export declare function getAssetHashFromPath(assetPath: string): string | null;
82
+ export declare function getOriginalPathFromAssetMap(assetMap: AssetMap | null, asset: {
83
+ path: string;
84
+ ext: string;
85
+ }): string | null;
72
86
  /** Given a directory, load the metadata.json and collect the assets for each platform. */
73
87
  export declare function collectAssetsAsync(dir: string): Promise<CollectedAssets>;
74
88
  export declare function filterOutAssetsThatAlreadyExistAsync(graphqlClient: ExpoGraphqlClient, uniqueAssetsWithStorageKey: (RawAsset & {
@@ -77,9 +91,17 @@ export declare function filterOutAssetsThatAlreadyExistAsync(graphqlClient: Expo
77
91
  storageKey: string;
78
92
  })[]>;
79
93
  type AssetUploadResult = {
94
+ /** All found assets within the exported folder per platform */
80
95
  assetCount: number;
96
+ /** The uploaded JS bundles, per platform */
97
+ launchAssetCount: number;
98
+ /** All unique assets within the exported folder with platforms combined */
81
99
  uniqueAssetCount: number;
100
+ /** All unique assets uploaded */
82
101
  uniqueUploadedAssetCount: number;
102
+ /** All (non-launch) asset original paths, used for logging */
103
+ uniqueUploadedAssetPaths: string[];
104
+ /** The asset limit received from the server */
83
105
  assetLimitPerUpdateGroup: number;
84
106
  };
85
107
  export declare function uploadAssetsAsync(graphqlClient: ExpoGraphqlClient, assetsForUpdateInfoGroup: CollectedAssets, projectId: string, updateSpinnerText?: (totalAssets: number, missingAssets: number) => void): Promise<AssetUploadResult>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isUploadedAssetCountAboveWarningThreshold = exports.uploadAssetsAsync = exports.filterOutAssetsThatAlreadyExistAsync = exports.collectAssetsAsync = exports.filterExportedPlatformsByFlag = exports.loadMetadata = exports.resolveInputDirectoryAsync = exports.buildBundlesAsync = exports.buildUnsortedUpdateInfoGroupAsync = exports.convertAssetToUpdateInfoGroupFormatAsync = exports.getStorageKeyForAssetAsync = exports.getStorageKey = exports.getBase64URLEncoding = exports.guessContentTypeFromExtension = exports.MetadataJoi = void 0;
3
+ exports.isUploadedAssetCountAboveWarningThreshold = exports.uploadAssetsAsync = exports.filterOutAssetsThatAlreadyExistAsync = exports.collectAssetsAsync = exports.getOriginalPathFromAssetMap = exports.getAssetHashFromPath = exports.loadAssetMapAsync = exports.filterExportedPlatformsByFlag = 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"));
@@ -16,6 +16,7 @@ const log_1 = tslib_1.__importDefault(require("../log"));
16
16
  const uploads_1 = require("../uploads");
17
17
  const expoCli_1 = require("../utils/expoCli");
18
18
  const chunk_1 = tslib_1.__importDefault(require("../utils/expodash/chunk"));
19
+ const filter_1 = require("../utils/expodash/filter");
19
20
  const uniqBy_1 = tslib_1.__importDefault(require("../utils/expodash/uniqBy"));
20
21
  const fileMetadataJoi = joi_1.default.object({
21
22
  assets: joi_1.default.array()
@@ -115,6 +116,7 @@ async function buildBundlesAsync({ projectDir, inputDir, exp, platformFlag, }) {
115
116
  '--output-dir',
116
117
  inputDir,
117
118
  '--dump-sourcemap',
119
+ '--dump-assetmap',
118
120
  '--platform',
119
121
  platformFlag,
120
122
  ]);
@@ -128,6 +130,7 @@ async function buildBundlesAsync({ projectDir, inputDir, exp, platformFlag, }) {
128
130
  '--experimental-bundle',
129
131
  '--non-interactive',
130
132
  '--dump-sourcemap',
133
+ '--dump-assetmap',
131
134
  '--platform',
132
135
  platformFlag,
133
136
  ]);
@@ -179,9 +182,42 @@ function filterExportedPlatformsByFlag(record, platformFlag) {
179
182
  return { [platform]: record[platform] };
180
183
  }
181
184
  exports.filterExportedPlatformsByFlag = filterExportedPlatformsByFlag;
185
+ /** Try to load the asset map for logging the names of assets published */
186
+ async function loadAssetMapAsync(distRoot) {
187
+ const assetMapPath = path_1.default.join(distRoot, 'assetmap.json');
188
+ if (!(await fs_extra_1.default.pathExists(assetMapPath))) {
189
+ return null;
190
+ }
191
+ const assetMap = json_file_1.default.read(path_1.default.join(distRoot, 'assetmap.json'));
192
+ // TODO: basic validation?
193
+ return assetMap;
194
+ }
195
+ exports.loadAssetMapAsync = loadAssetMapAsync;
196
+ // exposed for testing
197
+ function getAssetHashFromPath(assetPath) {
198
+ var _a;
199
+ const [, hash] = (_a = assetPath.match(new RegExp(/assets\/([a-z0-9]+)$/, 'i'))) !== null && _a !== void 0 ? _a : [];
200
+ return hash !== null && hash !== void 0 ? hash : null;
201
+ }
202
+ exports.getAssetHashFromPath = getAssetHashFromPath;
203
+ // exposed for testing
204
+ function getOriginalPathFromAssetMap(assetMap, asset) {
205
+ if (!assetMap) {
206
+ return null;
207
+ }
208
+ const assetHash = getAssetHashFromPath(asset.path);
209
+ const assetMapEntry = assetHash && assetMap[assetHash];
210
+ if (!assetMapEntry) {
211
+ return null;
212
+ }
213
+ const pathPrefix = assetMapEntry.httpServerLocation.substring('/assets'.length);
214
+ return `${pathPrefix}/${assetMapEntry.name}.${assetMapEntry.type}`;
215
+ }
216
+ exports.getOriginalPathFromAssetMap = getOriginalPathFromAssetMap;
182
217
  /** Given a directory, load the metadata.json and collect the assets for each platform. */
183
218
  async function collectAssetsAsync(dir) {
184
219
  const metadata = loadMetadata(dir);
220
+ const assetmap = await loadAssetMapAsync(dir);
185
221
  const collectedAssets = {};
186
222
  for (const platform of Object.keys(metadata.fileMetadata)) {
187
223
  collectedAssets[platform] = {
@@ -190,11 +226,15 @@ async function collectAssetsAsync(dir) {
190
226
  contentType: 'application/javascript',
191
227
  path: path_1.default.resolve(dir, metadata.fileMetadata[platform].bundle),
192
228
  },
193
- assets: metadata.fileMetadata[platform].assets.map(asset => ({
194
- fileExtension: asset.ext ? ensureLeadingPeriod(asset.ext) : undefined,
195
- contentType: guessContentTypeFromExtension(asset.ext),
196
- path: path_1.default.join(dir, asset.path),
197
- })),
229
+ assets: metadata.fileMetadata[platform].assets.map(asset => {
230
+ var _a;
231
+ return ({
232
+ fileExtension: asset.ext ? ensureLeadingPeriod(asset.ext) : undefined,
233
+ originalPath: (_a = getOriginalPathFromAssetMap(assetmap, asset)) !== null && _a !== void 0 ? _a : undefined,
234
+ contentType: guessContentTypeFromExtension(asset.ext),
235
+ path: path_1.default.join(dir, asset.path),
236
+ });
237
+ }),
198
238
  };
199
239
  }
200
240
  return collectedAssets;
@@ -218,7 +258,9 @@ exports.filterOutAssetsThatAlreadyExistAsync = filterOutAssetsThatAlreadyExistAs
218
258
  async function uploadAssetsAsync(graphqlClient, assetsForUpdateInfoGroup, projectId, updateSpinnerText) {
219
259
  let assets = [];
220
260
  let platform;
261
+ const launchAssets = [];
221
262
  for (platform in assetsForUpdateInfoGroup) {
263
+ launchAssets.push(assetsForUpdateInfoGroup[platform].launchAsset);
222
264
  assets = [
223
265
  ...assets,
224
266
  assetsForUpdateInfoGroup[platform].launchAsset,
@@ -236,6 +278,7 @@ async function uploadAssetsAsync(graphqlClient, assetsForUpdateInfoGroup, projec
236
278
  updateSpinnerText === null || updateSpinnerText === void 0 ? void 0 : updateSpinnerText(totalAssets, totalAssets);
237
279
  let missingAssets = await filterOutAssetsThatAlreadyExistAsync(graphqlClient, uniqueAssets);
238
280
  const uniqueUploadedAssetCount = missingAssets.length;
281
+ const uniqueUploadedAssetPaths = missingAssets.map(asset => asset.originalPath).filter(filter_1.truthy);
239
282
  const missingAssetChunks = (0, chunk_1.default)(missingAssets, 100);
240
283
  const specifications = [];
241
284
  for (const missingAssets of missingAssetChunks) {
@@ -263,8 +306,10 @@ async function uploadAssetsAsync(graphqlClient, assetsForUpdateInfoGroup, projec
263
306
  }
264
307
  return {
265
308
  assetCount: assets.length,
309
+ launchAssetCount: launchAssets.length,
266
310
  uniqueAssetCount: uniqueAssets.length,
267
311
  uniqueUploadedAssetCount,
312
+ uniqueUploadedAssetPaths,
268
313
  assetLimitPerUpdateGroup,
269
314
  };
270
315
  }