eas-cli 19.0.7 → 19.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,7 +9,7 @@ import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGr
9
9
  import { CustomBuildConfigMetadata } from '../project/customBuildConfig';
10
10
  import { Actor } from '../user/User';
11
11
  import { Client } from '../vcs/vcs';
12
- export declare function createBuildContextAsync<T extends Platform>({ buildProfileName, buildProfile, easJsonCliConfig, clearCache, localBuildOptions, nonInteractive, noWait, platform, projectDir, resourceClassFlag, message, actor, graphqlClient, analytics, vcsClient, getDynamicPrivateProjectConfigAsync, customBuildConfigMetadata, buildLoggerLevel, freezeCredentials, isVerboseLoggingEnabled, whatToTest, env, }: {
12
+ export declare function createBuildContextAsync<T extends Platform>({ buildProfileName, buildProfile, easJsonCliConfig, clearCache, localBuildOptions, nonInteractive, noWait, platform, projectDir, resourceClassFlag, message, actor, graphqlClient, analytics, vcsClient, getDynamicPrivateProjectConfigAsync, customBuildConfigMetadata, buildLoggerLevel, freezeCredentials, refreshAdHocProvisioningProfile: refreshAdHocProvisioningProfileFlag, isVerboseLoggingEnabled, whatToTest, env, }: {
13
13
  buildProfileName: string;
14
14
  buildProfile: BuildProfile<T>;
15
15
  easJsonCliConfig: EasJson['cli'];
@@ -29,6 +29,7 @@ export declare function createBuildContextAsync<T extends Platform>({ buildProfi
29
29
  customBuildConfigMetadata?: CustomBuildConfigMetadata;
30
30
  buildLoggerLevel?: LoggerLevel;
31
31
  freezeCredentials: boolean;
32
+ refreshAdHocProvisioningProfile?: boolean;
32
33
  isVerboseLoggingEnabled: boolean;
33
34
  whatToTest?: string;
34
35
  env: Record<string, string>;
@@ -16,7 +16,7 @@ const AnalyticsManager_1 = require("../analytics/AnalyticsManager");
16
16
  const context_1 = require("../credentials/context");
17
17
  const projectUtils_1 = require("../project/projectUtils");
18
18
  const workflow_1 = require("../project/workflow");
19
- async function createBuildContextAsync({ buildProfileName, buildProfile, easJsonCliConfig, clearCache = false, localBuildOptions, nonInteractive, noWait, platform, projectDir, resourceClassFlag, message, actor, graphqlClient, analytics, vcsClient, getDynamicPrivateProjectConfigAsync, customBuildConfigMetadata, buildLoggerLevel, freezeCredentials, isVerboseLoggingEnabled, whatToTest, env, }) {
19
+ async function createBuildContextAsync({ buildProfileName, buildProfile, easJsonCliConfig, clearCache = false, localBuildOptions, nonInteractive, noWait, platform, projectDir, resourceClassFlag, message, actor, graphqlClient, analytics, vcsClient, getDynamicPrivateProjectConfigAsync, customBuildConfigMetadata, buildLoggerLevel, freezeCredentials, refreshAdHocProvisioningProfile: refreshAdHocProvisioningProfileFlag, isVerboseLoggingEnabled, whatToTest, env, }) {
20
20
  const { exp, projectId } = await getDynamicPrivateProjectConfigAsync({
21
21
  env,
22
22
  });
@@ -33,6 +33,7 @@ async function createBuildContextAsync({ buildProfileName, buildProfile, easJson
33
33
  : buildProfile?.buildConfiguration === 'Debug') ??
34
34
  false;
35
35
  const requiredPackageManager = (0, package_manager_1.resolvePackageManager)(projectDir);
36
+ const refreshAdHocProvisioningProfile = refreshAdHocProvisioningProfileFlag ?? false;
36
37
  const credentialsCtx = new context_1.CredentialsContext({
37
38
  projectInfo: { exp, projectId },
38
39
  nonInteractive,
@@ -44,6 +45,7 @@ async function createBuildContextAsync({ buildProfileName, buildProfile, easJson
44
45
  easJsonCliConfig,
45
46
  vcsClient,
46
47
  freezeCredentials,
48
+ refreshAdHocProvisioningProfile,
47
49
  });
48
50
  const devClientProperties = getDevClientEventProperties({
49
51
  platform,
@@ -11,13 +11,17 @@ async function ensureIosCredentialsAsync(buildCtx, targets) {
11
11
  if (!shouldProvideCredentials(buildCtx)) {
12
12
  return;
13
13
  }
14
+ const { credentialsSource } = buildCtx.buildProfile;
15
+ if (buildCtx.credentialsCtx.refreshAdHocProvisioningProfile &&
16
+ credentialsSource === 'local') {
17
+ throw new Error('--refresh-ad-hoc-provisioning-profile cannot be used with credentialsSource "local". Use remote credentials or omit the flag.');
18
+ }
14
19
  const provider = new IosCredentialsProvider_1.default(buildCtx.credentialsCtx, {
15
20
  app: await (0, BuildCredentialsUtils_1.getAppFromContextAsync)(buildCtx.credentialsCtx),
16
21
  targets,
17
22
  distribution: buildCtx.buildProfile.distribution ?? 'store',
18
23
  enterpriseProvisioning: buildCtx.buildProfile.enterpriseProvisioning,
19
24
  });
20
- const { credentialsSource } = buildCtx.buildProfile;
21
25
  (0, credentials_1.logCredentialsSource)(credentialsSource, eas_build_job_1.Platform.IOS);
22
26
  return {
23
27
  credentials: await provider.getCredentialsAsync(credentialsSource),
@@ -91,6 +91,9 @@ async function prepareJobAsync(ctx, jobData) {
91
91
  // See: https://github.com/expo/eas-build/pull/454
92
92
  appId: ctx.projectId,
93
93
  initiatingUserId: ctx.user.id,
94
+ ...(ctx.credentialsCtx.refreshAdHocProvisioningProfile && {
95
+ refreshAdHocProvisioningProfile: true,
96
+ }),
94
97
  };
95
98
  return (0, eas_build_job_1.sanitizeBuildJob)(job);
96
99
  }
@@ -25,6 +25,7 @@ export interface BuildFlags {
25
25
  message?: string;
26
26
  buildLoggerLevel?: LoggerLevel;
27
27
  freezeCredentials: boolean;
28
+ refreshAdHocProvisioningProfile?: boolean;
28
29
  isVerboseLoggingEnabled?: boolean;
29
30
  whatToTest?: string;
30
31
  simulator?: SimulatorRunTarget;
@@ -243,6 +243,7 @@ async function prepareAndStartBuildAsync({ projectDir, flags, moreBuilds, buildP
243
243
  customBuildConfigMetadata,
244
244
  buildLoggerLevel: flags.buildLoggerLevel ?? (log_1.default.isDebug ? logger_1.LoggerLevel.DEBUG : undefined),
245
245
  freezeCredentials: flags.freezeCredentials,
246
+ refreshAdHocProvisioningProfile: flags.refreshAdHocProvisioningProfile,
246
247
  isVerboseLoggingEnabled: flags.isVerboseLoggingEnabled ?? false,
247
248
  whatToTest: flags.whatToTest,
248
249
  env,
@@ -31,4 +31,5 @@ export interface BuildFlags {
31
31
  message?: string;
32
32
  buildLoggerLevel?: LoggerLevel;
33
33
  freezeCredentials: boolean;
34
+ refreshAdHocProvisioningProfile?: boolean;
34
35
  }
@@ -21,6 +21,7 @@ export default class Build extends EasCommand {
21
21
  message: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
22
22
  'build-logger-level': import("@oclif/core/lib/interfaces").OptionFlag<LoggerLevel | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
23
23
  'freeze-credentials': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
24
+ 'refresh-ad-hoc-provisioning-profile': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
24
25
  'verbose-logs': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
25
26
  };
26
27
  static contextDefinition: {
@@ -92,6 +92,10 @@ class Build extends EasCommand_1.default {
92
92
  default: false,
93
93
  description: 'Prevent the build from updating credentials in non-interactive mode',
94
94
  }),
95
+ 'refresh-ad-hoc-provisioning-profile': core_1.Flags.boolean({
96
+ default: false,
97
+ description: 'Refresh managed ad-hoc provisioning profiles from App Store Connect before gathering build credentials',
98
+ }),
95
99
  'verbose-logs': core_1.Flags.boolean({
96
100
  default: false,
97
101
  description: 'Use verbose logs for the build process',
@@ -138,6 +142,14 @@ class Build extends EasCommand_1.default {
138
142
  }
139
143
  sanitizeFlags(flags) {
140
144
  const { json, nonInteractive } = (0, flags_1.resolveNonInteractiveAndJsonFlags)(flags);
145
+ if (flags['refresh-ad-hoc-provisioning-profile']) {
146
+ if (!nonInteractive) {
147
+ core_1.Errors.error('--refresh-ad-hoc-provisioning-profile can only be used in non-interactive mode.', { exit: 1 });
148
+ }
149
+ if (flags['freeze-credentials']) {
150
+ core_1.Errors.error('Cannot use --refresh-ad-hoc-provisioning-profile with --freeze-credentials.', { exit: 1 });
151
+ }
152
+ }
141
153
  if (!flags.local && flags.output) {
142
154
  core_1.Errors.error('--output is allowed only for local builds', { exit: 1 });
143
155
  }
@@ -185,6 +197,7 @@ class Build extends EasCommand_1.default {
185
197
  message,
186
198
  buildLoggerLevel: flags['build-logger-level'],
187
199
  freezeCredentials: flags['freeze-credentials'],
200
+ refreshAdHocProvisioningProfile: flags['refresh-ad-hoc-provisioning-profile'],
188
201
  isVerboseLoggingEnabled: flags['verbose-logs'],
189
202
  whatToTest: flags['what-to-test'],
190
203
  };
@@ -12,6 +12,7 @@ export default class BuildInternal extends EasCommand {
12
12
  profile: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
13
13
  'auto-submit': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
14
14
  'auto-submit-with-profile': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
15
+ 'refresh-ad-hoc-provisioning-profile': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
15
16
  };
16
17
  static contextDefinition: {
17
18
  vcsClient: import("../../commandUtils/context/VcsClientContextField").default;
@@ -37,6 +37,10 @@ class BuildInternal extends EasCommand_1.default {
37
37
  helpValue: 'PROFILE_NAME',
38
38
  exclusive: ['auto-submit'],
39
39
  }),
40
+ 'refresh-ad-hoc-provisioning-profile': core_1.Flags.boolean({
41
+ default: false,
42
+ description: 'Refresh managed ad-hoc provisioning profiles from App Store Connect before gathering build credentials',
43
+ }),
40
44
  };
41
45
  static contextDefinition = {
42
46
  ...this.ContextOptions.LoggedIn,
@@ -70,6 +74,7 @@ class BuildInternal extends EasCommand_1.default {
70
74
  profile: flags.profile,
71
75
  nonInteractive: true,
72
76
  freezeCredentials: false,
77
+ refreshAdHocProvisioningProfile: flags['refresh-ad-hoc-provisioning-profile'],
73
78
  wait: false,
74
79
  clearCache: false,
75
80
  json: true,
@@ -1,4 +1,5 @@
1
1
  import EasCommand from '../commandUtils/EasCommand';
2
+ export declare function detectProjectSdkVersionAsync(projectDir: string): Promise<string | undefined>;
2
3
  export default class Go extends EasCommand {
3
4
  static description: string;
4
5
  static hidden: boolean;
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.detectProjectSdkVersionAsync = detectProjectSdkVersionAsync;
3
4
  const tslib_1 = require("tslib");
5
+ const config_1 = require("@expo/config");
4
6
  const apple_utils_1 = require("@expo/apple-utils");
5
7
  const core_1 = require("@oclif/core");
6
8
  const chalk_1 = tslib_1.__importDefault(require("chalk"));
@@ -23,6 +25,7 @@ const WorkflowRunQuery_1 = require("../graphql/queries/WorkflowRunQuery");
23
25
  const log_1 = tslib_1.__importStar(require("../log"));
24
26
  const prompts_1 = require("../prompts");
25
27
  const ora_1 = require("../ora");
28
+ const expoConfig_1 = require("../project/expoConfig");
26
29
  const fetchOrCreateProjectIDForWriteToConfigWithConfirmationAsync_1 = require("../project/fetchOrCreateProjectIDForWriteToConfigWithConfirmationAsync");
27
30
  const uploadAccountScopedFileAsync_1 = require("../project/uploadAccountScopedFileAsync");
28
31
  const uploadAccountScopedProjectSourceAsync_1 = require("../project/uploadAccountScopedProjectSourceAsync");
@@ -34,6 +37,18 @@ const bundleIdentifier_1 = require("../project/ios/bundleIdentifier");
34
37
  function deriveBundleIdSlug(bundleId) {
35
38
  return bundleId.split('.').filter(Boolean).pop();
36
39
  }
40
+ async function detectProjectSdkVersionAsync(projectDir) {
41
+ const paths = (0, config_1.getConfigFilePaths)(projectDir);
42
+ if (!paths.staticConfigPath && !paths.dynamicConfigPath) {
43
+ return;
44
+ }
45
+ try {
46
+ return (await (0, expoConfig_1.getPrivateExpoConfigAsync)(projectDir)).sdkVersion;
47
+ }
48
+ catch {
49
+ return;
50
+ }
51
+ }
37
52
  const TESTFLIGHT_GROUP_NAME = 'Team (Expo)';
38
53
  async function setupTestFlightAsync(ascApp) {
39
54
  let group;
@@ -150,7 +165,11 @@ class Go extends EasCommand_1.default {
150
165
  nonInteractive: false,
151
166
  });
152
167
  log_1.default.withTick(`Logged in as ${chalk_1.default.cyan((0, User_1.getActorDisplayName)(actor))}`);
153
- const sdkVersion = flags['sdk-version'];
168
+ const detectedSdkVersion = await detectProjectSdkVersionAsync(process.cwd());
169
+ if (detectedSdkVersion && !flags['sdk-version']) {
170
+ log_1.default.log(`Current project using SDK ${detectedSdkVersion.split('.')[0]}. Auto-selected same version. To use a different version, pass --sdk-version.`);
171
+ }
172
+ const sdkVersion = flags['sdk-version'] ?? detectedSdkVersion;
154
173
  const bundleId = flags['bundle-id'] ?? this.generateBundleId(actor);
155
174
  if (!(0, bundleIdentifier_1.isBundleIdentifierValid)(bundleId)) {
156
175
  throw new Error(`"${bundleId}" is not a valid iOS bundle identifier. ${bundleIdentifier_1.INVALID_BUNDLE_IDENTIFIER_MESSAGE} Pass a valid identifier with --bundle-id.`);
@@ -174,7 +193,8 @@ class Go extends EasCommand_1.default {
174
193
  setupSpinner.stop();
175
194
  log_1.default.markFreshLine();
176
195
  });
177
- const { workflowUrl, workflowRunId } = await this.dispatchWorkflowAsync(graphqlClient, projectId, actor, bundleId, appName, ascApp.id, sdkVersion, tmpDir, vcsClient);
196
+ const { workflowUrl, workflowRunId, sdkVersion: resolvedSdkVersion, } = await this.dispatchWorkflowAsync(graphqlClient, projectId, actor, bundleId, appName, ascApp.id, sdkVersion, tmpDir, vcsClient);
197
+ log_1.default.withTick(`Using Expo Go SDK ${chalk_1.default.cyan(resolvedSdkVersion.split('.')[0])}`);
178
198
  log_1.default.withTick(`Build started: ${chalk_1.default.cyan(workflowUrl)}`);
179
199
  const status = await this.monitorWorkflowJobsAsync(graphqlClient, workflowRunId);
180
200
  if (status === generated_1.WorkflowRunStatus.Failure) {
@@ -319,7 +339,7 @@ class Go extends EasCommand_1.default {
319
339
  },
320
340
  });
321
341
  const workflowUrl = (0, url_1.getWorkflowRunUrl)(account.name, deriveBundleIdSlug(bundleId), result.id);
322
- return { workflowUrl, workflowRunId: result.id };
342
+ return { workflowUrl, workflowRunId: result.id, sdkVersion: repackConfig.sdkVersion };
323
343
  }
324
344
  async monitorWorkflowJobsAsync(graphqlClient, workflowRunId) {
325
345
  const EXPECTED_BUILD_DURATION_SECONDS = 5 * 60;
@@ -20,6 +20,7 @@ export declare class CredentialsContext {
20
20
  readonly nonInteractive: boolean;
21
21
  readonly autoAcceptCredentialReuse: boolean;
22
22
  readonly freezeCredentials: boolean;
23
+ readonly refreshAdHocProvisioningProfile: boolean;
23
24
  readonly projectDir: string;
24
25
  readonly user: Actor;
25
26
  readonly graphqlClient: ExpoGraphqlClient;
@@ -40,6 +41,7 @@ export declare class CredentialsContext {
40
41
  vcsClient: Client;
41
42
  freezeCredentials?: boolean;
42
43
  autoAcceptCredentialReuse?: boolean;
44
+ refreshAdHocProvisioningProfile?: boolean;
43
45
  env?: Env;
44
46
  });
45
47
  get hasProjectContext(): boolean;
@@ -18,6 +18,7 @@ class CredentialsContext {
18
18
  nonInteractive;
19
19
  autoAcceptCredentialReuse;
20
20
  freezeCredentials = false;
21
+ refreshAdHocProvisioningProfile = false;
21
22
  projectDir;
22
23
  user;
23
24
  graphqlClient;
@@ -39,6 +40,7 @@ class CredentialsContext {
39
40
  this.autoAcceptCredentialReuse = options.autoAcceptCredentialReuse ?? false;
40
41
  this.projectInfo = options.projectInfo;
41
42
  this.freezeCredentials = options.freezeCredentials ?? false;
43
+ this.refreshAdHocProvisioningProfile = options.refreshAdHocProvisioningProfile ?? false;
42
44
  this.usesBroadcastPushNotifications =
43
45
  options.projectInfo?.exp.ios?.usesBroadcastPushNotifications ?? false;
44
46
  }
@@ -1,3 +1,5 @@
1
1
  import { AppleDevice, AppleDeviceFragment } from '../../../graphql/generated';
2
+ import { ApplePlatform } from '../appstore/constants';
3
+ export declare function filterDevicesForApplePlatform(devices: AppleDeviceFragment[], applePlatform: ApplePlatform): AppleDeviceFragment[];
2
4
  export declare function chooseDevicesAsync(allDevices: AppleDeviceFragment[], preselectedDeviceIdentifiers?: string[]): Promise<AppleDevice[]>;
3
5
  export declare function formatDeviceLabel(device: AppleDeviceFragment): string;
@@ -1,9 +1,30 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.filterDevicesForApplePlatform = filterDevicesForApplePlatform;
3
4
  exports.chooseDevicesAsync = chooseDevicesAsync;
4
5
  exports.formatDeviceLabel = formatDeviceLabel;
5
6
  const prompts_1 = require("../.././../prompts");
7
+ const generated_1 = require("../../../graphql/generated");
6
8
  const AppleDevice_1 = require("../../../graphql/types/credentials/AppleDevice");
9
+ const constants_1 = require("../appstore/constants");
10
+ function filterDevicesForApplePlatform(devices, applePlatform) {
11
+ if (applePlatform === constants_1.ApplePlatform.TV_OS) {
12
+ throw new Error('Filtering for tvOS is not supported yet');
13
+ }
14
+ if (applePlatform === constants_1.ApplePlatform.VISION_OS) {
15
+ throw new Error('Filtering for visionOS is not supported yet');
16
+ }
17
+ return devices.filter(device => isDeviceCompatibleWithApplePlatform(device, applePlatform));
18
+ }
19
+ function isDeviceCompatibleWithApplePlatform(device, applePlatform) {
20
+ switch (applePlatform) {
21
+ case constants_1.ApplePlatform.IOS:
22
+ return (device.deviceClass === generated_1.AppleDeviceClass.Iphone ||
23
+ device.deviceClass === generated_1.AppleDeviceClass.Ipad);
24
+ case constants_1.ApplePlatform.MAC_OS:
25
+ return device.deviceClass === generated_1.AppleDeviceClass.Mac;
26
+ }
27
+ }
7
28
  async function chooseDevicesAsync(allDevices, preselectedDeviceIdentifiers = []) {
8
29
  const preselectedDeviceIdentifierSet = new Set(preselectedDeviceIdentifiers);
9
30
  const isSelected = (device) => preselectedDeviceIdentifierSet.size === 0 ||
@@ -16,6 +16,7 @@ export declare class SetUpAdhocProvisioningProfile {
16
16
  private shouldUseExistingProfileAsync;
17
17
  private promptForReuseActionAsync;
18
18
  private registerDevicesAsync;
19
+ private ensureAppStoreAuthenticatedForAdhocRefreshAsync;
19
20
  }
20
21
  export declare function doUDIDsMatch(udidsA: string[], udidsB: string[]): boolean;
21
22
  export {};
@@ -14,12 +14,16 @@ const DeviceUtils_1 = require("./DeviceUtils");
14
14
  const SetUpDistributionCertificate_1 = require("./SetUpDistributionCertificate");
15
15
  const action_1 = tslib_1.__importStar(require("../../../devices/actions/create/action"));
16
16
  const generated_1 = require("../../../graphql/generated");
17
+ const AppStoreConnectApiKeyQuery_1 = require("../../../graphql/queries/AppStoreConnectApiKeyQuery");
17
18
  const log_1 = tslib_1.__importDefault(require("../../../log"));
18
19
  const target_1 = require("../../../project/ios/target");
19
20
  const prompts_1 = require("../../../prompts");
20
21
  const differenceBy_1 = tslib_1.__importDefault(require("../../../utils/expodash/differenceBy"));
21
22
  const errors_1 = require("../../errors");
23
+ const GraphqlClient_1 = require("../api/GraphqlClient");
24
+ const authenticateTypes_1 = require("../appstore/authenticateTypes");
22
25
  const constants_1 = require("../appstore/constants");
26
+ const resolveCredentials_1 = require("../appstore/resolveCredentials");
23
27
  const validateProvisioningProfile_1 = require("../validators/validateProvisioningProfile");
24
28
  var ReuseAction;
25
29
  (function (ReuseAction) {
@@ -34,7 +38,14 @@ class SetUpAdhocProvisioningProfile {
34
38
  }
35
39
  async runAsync(ctx) {
36
40
  const { app } = this.options;
41
+ if (ctx.refreshAdHocProvisioningProfile && ctx.freezeCredentials) {
42
+ throw new Error('Cannot refresh ad-hoc provisioning profile when credentials are frozen. Remove --freeze-credentials or --refresh-ad-hoc-provisioning-profile.');
43
+ }
37
44
  const distCert = await new SetUpDistributionCertificate_1.SetUpDistributionCertificate(app, generated_1.IosDistributionType.AdHoc).runAsync(ctx);
45
+ if (ctx.nonInteractive && ctx.refreshAdHocProvisioningProfile) {
46
+ await this.ensureAppStoreAuthenticatedForAdhocRefreshAsync(ctx, app);
47
+ return await this.runWithDistributionCertificateAsync(ctx, distCert);
48
+ }
38
49
  const areBuildCredentialsSetup = await this.areBuildCredentialsSetupAsync(ctx);
39
50
  if (ctx.nonInteractive) {
40
51
  if (areBuildCredentialsSetup) {
@@ -66,6 +77,9 @@ class SetUpAdhocProvisioningProfile {
66
77
  // 2. Fetch devices registered on EAS servers
67
78
  let registeredAppleDevices = await ctx.ios.getDevicesForAppleTeamAsync(ctx.graphqlClient, app, appleTeam);
68
79
  if (registeredAppleDevices.length === 0) {
80
+ if (ctx.nonInteractive) {
81
+ throw new Error('No devices are registered for this Apple team. Register devices with eas device:create first.');
82
+ }
69
83
  const shouldRegisterDevices = await (0, prompts_1.confirmAsync)({
70
84
  message: `You don't have any registered devices yet. Would you like to register them now?`,
71
85
  initial: true,
@@ -79,9 +93,11 @@ class SetUpAdhocProvisioningProfile {
79
93
  }
80
94
  // 3. Choose devices for internal distribution
81
95
  const provisionedDeviceIdentifiers = (currentBuildCredentials?.provisioningProfile?.appleDevices ?? []).map(i => i.identifier);
82
- const chosenDevices = await (0, DeviceUtils_1.chooseDevicesAsync)(registeredAppleDevices, provisionedDeviceIdentifiers);
83
- // 4. Reuse or create the profile on Apple Developer Portal
84
96
  const applePlatform = (0, target_1.getApplePlatformFromTarget)(target);
97
+ const chosenDevices = ctx.nonInteractive && ctx.refreshAdHocProvisioningProfile
98
+ ? (0, DeviceUtils_1.filterDevicesForApplePlatform)(registeredAppleDevices, applePlatform)
99
+ : await (0, DeviceUtils_1.chooseDevicesAsync)(registeredAppleDevices, provisionedDeviceIdentifiers);
100
+ // 4. Reuse or create the profile on Apple Developer Portal
85
101
  const profileType = applePlatform === constants_1.ApplePlatform.TV_OS
86
102
  ? apple_utils_1.ProfileType.TVOS_APP_ADHOC
87
103
  : apple_utils_1.ProfileType.IOS_APP_ADHOC;
@@ -106,18 +122,23 @@ class SetUpAdhocProvisioningProfile {
106
122
  log_1.default.warn(`- ${(0, DeviceUtils_1.formatDeviceLabel)(missingDevice)}`);
107
123
  }
108
124
  log_1.default.log('Most commonly devices fail to to be provisioned while they are still being processed by Apple, which can take up to 24-72 hours. Check your Apple Developer Portal page at https://developer.apple.com/account/resources/devices/list, the devices in "Processing" status cannot be provisioned yet');
109
- const shouldContinue = await (0, prompts_1.selectAsync)('Do you want to continue without provisioning these devices?', [
110
- {
111
- title: 'Yes',
112
- value: true,
113
- },
114
- {
115
- title: 'No (EAS CLI will exit)',
116
- value: false,
117
- },
118
- ]);
119
- if (!shouldContinue) {
120
- core_1.Errors.exit(1);
125
+ if (ctx.nonInteractive && ctx.refreshAdHocProvisioningProfile) {
126
+ // Continue without prompting in non-interactive refresh mode.
127
+ }
128
+ else {
129
+ const shouldContinue = await (0, prompts_1.selectAsync)('Do you want to continue without provisioning these devices?', [
130
+ {
131
+ title: 'Yes',
132
+ value: true,
133
+ },
134
+ {
135
+ title: 'No (EAS CLI will exit)',
136
+ value: false,
137
+ },
138
+ ]);
139
+ if (!shouldContinue) {
140
+ core_1.Errors.exit(1);
141
+ }
121
142
  }
122
143
  }
123
144
  // 7. Create (or update) app build credentials
@@ -237,8 +258,49 @@ class SetUpAdhocProvisioningProfile {
237
258
  }
238
259
  }
239
260
  }
261
+ async ensureAppStoreAuthenticatedForAdhocRefreshAsync(ctx, app) {
262
+ if ((0, resolveCredentials_1.hasAscEnvVars)()) {
263
+ await ctx.appStore.ensureAuthenticatedAsync({ mode: authenticateTypes_1.AuthenticationMode.API_KEY });
264
+ return;
265
+ }
266
+ const resolvedKey = await resolveAscApiKeyForAppCredentialsAsync({
267
+ graphqlClient: ctx.graphqlClient,
268
+ app,
269
+ });
270
+ if (!resolvedKey) {
271
+ throw new Error('No App Store Connect API Key found for ad-hoc provisioning profile refresh. In non-interactive mode, provide one via:\n' +
272
+ ' - Environment variables: EXPO_ASC_API_KEY_PATH, EXPO_ASC_KEY_ID, EXPO_ASC_ISSUER_ID\n' +
273
+ ' - EAS credentials service: configure an App Store Connect API Key for submissions on this app');
274
+ }
275
+ await ctx.appStore.ensureAuthenticatedAsync({
276
+ mode: authenticateTypes_1.AuthenticationMode.API_KEY,
277
+ ascApiKey: resolvedKey.ascApiKey,
278
+ teamId: resolvedKey.teamId,
279
+ teamName: resolvedKey.teamName,
280
+ // Provide a non-enterprise team type to avoid interactive team-type resolution.
281
+ // Ad-hoc profile handling below uses explicit ProfileType and does not branch on team.inHouse.
282
+ teamType: authenticateTypes_1.AppleTeamType.COMPANY_OR_ORGANIZATION,
283
+ });
284
+ }
240
285
  }
241
286
  exports.SetUpAdhocProvisioningProfile = SetUpAdhocProvisioningProfile;
287
+ async function resolveAscApiKeyForAppCredentialsAsync({ graphqlClient, app, }) {
288
+ const ascKeyFragment = await (0, GraphqlClient_1.getAscApiKeyForAppSubmissionsAsync)(graphqlClient, app);
289
+ if (!ascKeyFragment) {
290
+ return null;
291
+ }
292
+ log_1.default.log('Using App Store Connect API Key from EAS credentials service.');
293
+ const fullKey = await AppStoreConnectApiKeyQuery_1.AppStoreConnectApiKeyQuery.getByIdAsync(graphqlClient, ascKeyFragment.id);
294
+ return {
295
+ ascApiKey: {
296
+ keyP8: fullKey.keyP8,
297
+ keyId: fullKey.keyIdentifier,
298
+ issuerId: fullKey.issuerIdentifier,
299
+ },
300
+ teamId: ascKeyFragment.appleTeam?.appleTeamIdentifier,
301
+ teamName: ascKeyFragment.appleTeam?.appleTeamName ?? undefined,
302
+ };
303
+ }
242
304
  function doUDIDsMatch(udidsA, udidsB) {
243
305
  const setA = new Set(udidsA);
244
306
  const setB = new Set(udidsB);
@@ -36,6 +36,14 @@ class SetUpTargetBuildCredentials {
36
36
  }
37
37
  async setupBuildCredentialsAsync(ctx) {
38
38
  const { app, distribution, enterpriseProvisioning, target } = this.options;
39
+ if (ctx.refreshAdHocProvisioningProfile) {
40
+ if (distribution !== 'internal') {
41
+ throw new Error('--refresh-ad-hoc-provisioning-profile is only supported for internal distribution builds.');
42
+ }
43
+ if (enterpriseProvisioning === 'universal') {
44
+ throw new Error('--refresh-ad-hoc-provisioning-profile is only supported for ad-hoc internal builds.');
45
+ }
46
+ }
39
47
  if (distribution === 'internal') {
40
48
  if (enterpriseProvisioning === 'adhoc') {
41
49
  return await new SetUpAdhocProvisioningProfile_1.SetUpAdhocProvisioningProfile({ app, target }).runAsync(ctx);