Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ This is the log of notable changes to EAS CLI and related packages.

### 🎉 New features

- [eas-cli] Add `--refresh-ad-hoc-provisioning-profile` flag to refresh managed ad-hoc provisioning profiles from App Store Connect before gathering build credentials in non-interactive mode. ([#3716](https://github.com/expo/eas-cli/pull/3716) by [@sswrk](https://github.com/sswrk))

### 🐛 Bug fixes

### 🧹 Chores
Expand Down
5 changes: 5 additions & 0 deletions packages/eas-cli/src/build/createContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export async function createBuildContextAsync<T extends Platform>({
customBuildConfigMetadata,
buildLoggerLevel,
freezeCredentials,
refreshAdHocProvisioningProfile: refreshAdHocProvisioningProfileFlag,
isVerboseLoggingEnabled,
whatToTest,
env,
Expand All @@ -65,6 +66,7 @@ export async function createBuildContextAsync<T extends Platform>({
customBuildConfigMetadata?: CustomBuildConfigMetadata;
buildLoggerLevel?: LoggerLevel;
freezeCredentials: boolean;
refreshAdHocProvisioningProfile?: boolean;
isVerboseLoggingEnabled: boolean;
whatToTest?: string;
env: Record<string, string>;
Expand All @@ -90,6 +92,8 @@ export async function createBuildContextAsync<T extends Platform>({

const requiredPackageManager = resolvePackageManager(projectDir);

const refreshAdHocProvisioningProfile = refreshAdHocProvisioningProfileFlag ?? false;

const credentialsCtx = new CredentialsContext({
projectInfo: { exp, projectId },
nonInteractive,
Expand All @@ -101,6 +105,7 @@ export async function createBuildContextAsync<T extends Platform>({
easJsonCliConfig,
vcsClient,
freezeCredentials,
refreshAdHocProvisioningProfile,
});

const devClientProperties = getDevClientEventProperties({
Expand Down
40 changes: 40 additions & 0 deletions packages/eas-cli/src/build/ios/__tests__/credentials-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Platform } from '@expo/eas-build-job';
import { CredentialsSource } from '@expo/eas-json';

import { BuildContext } from '../../context';
import { ensureIosCredentialsAsync } from '../credentials';

describe(ensureIosCredentialsAsync, () => {
it('errors when refresh is enabled with local credentials source', async () => {
const buildCtx = {
buildProfile: {
credentialsSource: CredentialsSource.LOCAL,
simulator: false,
withoutCredentials: false,
},
credentialsCtx: {
refreshAdHocProvisioningProfile: true,
},
} as BuildContext<Platform.IOS>;

await expect(ensureIosCredentialsAsync(buildCtx, [])).rejects.toThrow(
'--refresh-ad-hoc-provisioning-profile cannot be used with credentialsSource "local". Use remote credentials or omit the flag.'
);
});

it('does not reject refresh when credentials source is remote', async () => {
const buildCtx = {
buildProfile: {
credentialsSource: CredentialsSource.REMOTE,
simulator: true,
withoutCredentials: false,
distribution: 'internal',
},
credentialsCtx: {
refreshAdHocProvisioningProfile: true,
},
} as BuildContext<Platform.IOS>;

await expect(ensureIosCredentialsAsync(buildCtx, [])).resolves.toBeUndefined();
});
});
12 changes: 10 additions & 2 deletions packages/eas-cli/src/build/ios/credentials.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,23 @@ export async function ensureIosCredentialsAsync(
return;
}

const { credentialsSource } = buildCtx.buildProfile;
if (
buildCtx.credentialsCtx.refreshAdHocProvisioningProfile &&
credentialsSource === 'local'
) {
throw new Error(
'--refresh-ad-hoc-provisioning-profile cannot be used with credentialsSource "local". Use remote credentials or omit the flag.'
);
}

const provider = new IosCredentialsProvider(buildCtx.credentialsCtx, {
app: await getAppFromContextAsync(buildCtx.credentialsCtx),
targets,
distribution: buildCtx.buildProfile.distribution ?? 'store',
enterpriseProvisioning: buildCtx.buildProfile.enterpriseProvisioning,
});

const { credentialsSource } = buildCtx.buildProfile;

logCredentialsSource(credentialsSource, Platform.IOS);
return {
credentials: await provider.getCredentialsAsync(credentialsSource),
Expand Down
2 changes: 2 additions & 0 deletions packages/eas-cli/src/build/runBuildAndSubmit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ export interface BuildFlags {
message?: string;
buildLoggerLevel?: LoggerLevel;
freezeCredentials: boolean;
refreshAdHocProvisioningProfile?: boolean;
isVerboseLoggingEnabled?: boolean;
whatToTest?: string;
simulator?: SimulatorRunTarget;
Expand Down Expand Up @@ -413,6 +414,7 @@ async function prepareAndStartBuildAsync({
customBuildConfigMetadata,
buildLoggerLevel: flags.buildLoggerLevel ?? (Log.isDebug ? LoggerLevel.DEBUG : undefined),
freezeCredentials: flags.freezeCredentials,
refreshAdHocProvisioningProfile: flags.refreshAdHocProvisioningProfile,
isVerboseLoggingEnabled: flags.isVerboseLoggingEnabled ?? false,
whatToTest: flags.whatToTest,
env,
Expand Down
1 change: 1 addition & 0 deletions packages/eas-cli/src/build/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,5 @@ export interface BuildFlags {
message?: string;
buildLoggerLevel?: LoggerLevel;
freezeCredentials: boolean;
refreshAdHocProvisioningProfile?: boolean;
}
21 changes: 21 additions & 0 deletions packages/eas-cli/src/commands/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ interface RawBuildFlags {
message?: string;
'build-logger-level'?: LoggerLevel;
'freeze-credentials': boolean;
'refresh-ad-hoc-provisioning-profile': boolean;
'verbose-logs'?: boolean;
'what-to-test'?: string;
}
Expand Down Expand Up @@ -121,6 +122,11 @@ export default class Build extends EasCommand {
default: false,
description: 'Prevent the build from updating credentials in non-interactive mode',
}),
'refresh-ad-hoc-provisioning-profile': Flags.boolean({
default: false,
description:
'Refresh managed ad-hoc provisioning profiles from App Store Connect before gathering build credentials',
}),
'verbose-logs': Flags.boolean({
default: false,
description: 'Use verbose logs for the build process',
Expand Down Expand Up @@ -188,6 +194,20 @@ export default class Build extends EasCommand {
flags: RawBuildFlags
): Omit<BuildFlags, 'requestedPlatform'> & { requestedPlatform?: RequestedPlatform } {
const { json, nonInteractive } = resolveNonInteractiveAndJsonFlags(flags);
if (flags['refresh-ad-hoc-provisioning-profile']) {
if (!nonInteractive) {
Errors.error(
'--refresh-ad-hoc-provisioning-profile can only be used in non-interactive mode.',
{ exit: 1 }
);
}
if (flags['freeze-credentials']) {
Errors.error(
'Cannot use --refresh-ad-hoc-provisioning-profile with --freeze-credentials.',
{ exit: 1 }
);
}
}
if (!flags.local && flags.output) {
Errors.error('--output is allowed only for local builds', { exit: 1 });
}
Expand Down Expand Up @@ -249,6 +269,7 @@ export default class Build extends EasCommand {
message,
buildLoggerLevel: flags['build-logger-level'],
freezeCredentials: flags['freeze-credentials'],
refreshAdHocProvisioningProfile: flags['refresh-ad-hoc-provisioning-profile'],
isVerboseLoggingEnabled: flags['verbose-logs'],
whatToTest: flags['what-to-test'],
};
Expand Down
3 changes: 3 additions & 0 deletions packages/eas-cli/src/credentials/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export class CredentialsContext {
public readonly nonInteractive: boolean;
public readonly autoAcceptCredentialReuse: boolean;
public readonly freezeCredentials: boolean = false;
public readonly refreshAdHocProvisioningProfile: boolean = false;
public readonly projectDir: string;
public readonly user: Actor;
public readonly graphqlClient: ExpoGraphqlClient;
Expand All @@ -52,6 +53,7 @@ export class CredentialsContext {
vcsClient: Client;
freezeCredentials?: boolean;
autoAcceptCredentialReuse?: boolean;
refreshAdHocProvisioningProfile?: boolean;
env?: Env;
}
) {
Expand All @@ -65,6 +67,7 @@ export class CredentialsContext {
this.autoAcceptCredentialReuse = options.autoAcceptCredentialReuse ?? false;
this.projectInfo = options.projectInfo;
this.freezeCredentials = options.freezeCredentials ?? false;
this.refreshAdHocProvisioningProfile = options.refreshAdHocProvisioningProfile ?? false;
this.usesBroadcastPushNotifications =
options.projectInfo?.exp.ios?.usesBroadcastPushNotifications ?? false;
}
Expand Down
33 changes: 32 additions & 1 deletion packages/eas-cli/src/credentials/ios/actions/DeviceUtils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,37 @@
import { promptAsync } from '../.././../prompts';
import { AppleDevice, AppleDeviceFragment } from '../../../graphql/generated';
import { AppleDevice, AppleDeviceClass, AppleDeviceFragment } from '../../../graphql/generated';
import { APPLE_DEVICE_CLASS_LABELS } from '../../../graphql/types/credentials/AppleDevice';
import { ApplePlatform } from '../appstore/constants';

export function filterDevicesForApplePlatform(
devices: AppleDeviceFragment[],
applePlatform: ApplePlatform
): AppleDeviceFragment[] {
if (applePlatform === ApplePlatform.TV_OS) {
throw new Error('Filtering for tvOS is not supported yet');
}

if (applePlatform === ApplePlatform.VISION_OS) {
throw new Error('Filtering for visionOS is not supported yet');
}

return devices.filter(device => isDeviceCompatibleWithApplePlatform(device, applePlatform));
}

function isDeviceCompatibleWithApplePlatform(
device: AppleDeviceFragment,
applePlatform: Exclude<ApplePlatform, ApplePlatform.TV_OS | ApplePlatform.VISION_OS>
): boolean {
switch (applePlatform) {
case ApplePlatform.IOS:
return (
device.deviceClass === AppleDeviceClass.Iphone ||
device.deviceClass === AppleDeviceClass.Ipad
);
case ApplePlatform.MAC_OS:
return device.deviceClass === AppleDeviceClass.Mac;
}
}

export async function chooseDevicesAsync(
allDevices: AppleDeviceFragment[],
Expand Down
Loading
Loading