From 1a7edbea06e660e06bc29c81315310ecb3f341ee Mon Sep 17 00:00:00 2001 From: Quinlan Jung Date: Mon, 26 Apr 2021 12:10:27 -0700 Subject: [PATCH] [eas-cli] merge everything from actions/new to actions (#364) delete unused actions delete old inner class remove uneeded dist cert utils merge dist cert utils remove unused functions of pprofile utils pop out new directory --- packages/eas-cli/src/build/ios/credentials.ts | 2 +- .../credentialsJson/__tests__/update-test.ts | 2 +- .../__tests__/IosCredentialsProvider-test.ts | 2 +- .../ios/actions/{new => }/AppleTeamUtils.ts | 6 +- .../{new => }/BuildCredentialsUtils.ts | 13 +- .../actions/ConfigureProvisioningProfile.ts | 128 +++++---- .../actions/CreateDistributionCertificate.ts | 41 +-- .../{new => }/CreateProvisioningProfile.ts | 22 +- .../ios/actions/{new => }/DeviceUtils.ts | 6 +- .../actions/DistributionCertificateUtils.ts | 259 ++++++++++-------- .../ios/actions/ProvisioningProfileUtils.ts | 57 ---- .../actions/RemoveDistributionCertificate.ts | 114 ++++---- .../ios/actions/RemoveProvisioningProfile.ts | 66 ++--- .../SetupAdhocProvisioningProfile.ts | 16 +- .../ios/actions/SetupBuildCredentials.ts | 102 +------ ...etupBuildCredentialsFromCredentialsJson.ts | 16 +- .../{new => }/SetupDistributionCertificate.ts | 16 +- .../SetupInternalProvisioningProfile.ts | 10 +- .../{new => }/SetupProvisioningProfile.ts | 16 +- .../ios/actions/UpdateCredentialsJson.ts | 18 +- .../actions/UpdateDistributionCertificate.ts | 87 ------ .../ios/actions/UseDistributionCertificate.ts | 34 --- .../__mocks__/ConfigureProvisioningProfile.ts | 10 +- .../__mocks__/CreateProvisioningProfile.ts | 10 +- .../__mocks__/SetupDistributionCertificate.ts | 8 +- .../ConfigureProvisioningProfile-test.ts | 12 +- .../CreateProvisioningProfile-test.ts | 12 +- .../DistributionCertificateUtils-test.ts | 6 +- .../RemoveDistributionCertificate-test.ts | 8 +- .../RemoveProvisioningProfile-test.ts | 2 +- ...uildCredentialsFromCredentialsJson-test.ts | 18 +- .../SetupInternalProvisioningProfile-test.ts | 15 +- .../SetupProvisioningProfile-test.ts | 20 +- .../DistributionCertificateUtils-test.ts.snap | 0 .../new/ConfigureProvisioningProfile.ts | 113 -------- .../new/CreateDistributionCertificate.ts | 16 -- .../new/DistributionCertificateUtils.ts | 142 ---------- .../new/RemoveDistributionCertificate.ts | 90 ------ .../actions/new/RemoveProvisioningProfile.ts | 32 --- .../ios/actions/new/UpdateCredentialsJson.ts | 20 -- .../src/credentials/manager/ManageIos.ts | 18 +- 41 files changed, 437 insertions(+), 1148 deletions(-) rename packages/eas-cli/src/credentials/ios/actions/{new => }/AppleTeamUtils.ts (69%) rename packages/eas-cli/src/credentials/ios/actions/{new => }/BuildCredentialsUtils.ts (91%) rename packages/eas-cli/src/credentials/ios/actions/{new => }/CreateProvisioningProfile.ts (77%) rename packages/eas-cli/src/credentials/ios/actions/{new => }/DeviceUtils.ts (85%) rename packages/eas-cli/src/credentials/ios/actions/{new => }/SetupAdhocProvisioningProfile.ts (95%) rename packages/eas-cli/src/credentials/ios/actions/{new => }/SetupBuildCredentialsFromCredentialsJson.ts (94%) rename packages/eas-cli/src/credentials/ios/actions/{new => }/SetupDistributionCertificate.ts (92%) rename packages/eas-cli/src/credentials/ios/actions/{new => }/SetupInternalProvisioningProfile.ts (95%) rename packages/eas-cli/src/credentials/ios/actions/{new => }/SetupProvisioningProfile.ts (90%) delete mode 100644 packages/eas-cli/src/credentials/ios/actions/UpdateDistributionCertificate.ts delete mode 100644 packages/eas-cli/src/credentials/ios/actions/UseDistributionCertificate.ts rename packages/eas-cli/src/credentials/ios/actions/{new => }/__mocks__/ConfigureProvisioningProfile.ts (57%) rename packages/eas-cli/src/credentials/ios/actions/{new => }/__mocks__/CreateProvisioningProfile.ts (51%) rename packages/eas-cli/src/credentials/ios/actions/{new => }/__mocks__/SetupDistributionCertificate.ts (59%) rename packages/eas-cli/src/credentials/ios/actions/{new => }/__tests__/ConfigureProvisioningProfile-test.ts (87%) rename packages/eas-cli/src/credentials/ios/actions/{new => }/__tests__/CreateProvisioningProfile-test.ts (84%) rename packages/eas-cli/src/credentials/ios/actions/{new => }/__tests__/DistributionCertificateUtils-test.ts (73%) rename packages/eas-cli/src/credentials/ios/actions/{new => }/__tests__/RemoveDistributionCertificate-test.ts (94%) rename packages/eas-cli/src/credentials/ios/actions/{new => }/__tests__/RemoveProvisioningProfile-test.ts (91%) rename packages/eas-cli/src/credentials/ios/actions/{new => }/__tests__/SetupBuildCredentialsFromCredentialsJson-test.ts (94%) rename packages/eas-cli/src/credentials/ios/actions/{new => }/__tests__/SetupInternalProvisioningProfile-test.ts (96%) rename packages/eas-cli/src/credentials/ios/actions/{new => }/__tests__/SetupProvisioningProfile-test.ts (91%) rename packages/eas-cli/src/credentials/ios/actions/{new => }/__tests__/__snapshots__/DistributionCertificateUtils-test.ts.snap (100%) delete mode 100644 packages/eas-cli/src/credentials/ios/actions/new/ConfigureProvisioningProfile.ts delete mode 100644 packages/eas-cli/src/credentials/ios/actions/new/CreateDistributionCertificate.ts delete mode 100644 packages/eas-cli/src/credentials/ios/actions/new/DistributionCertificateUtils.ts delete mode 100644 packages/eas-cli/src/credentials/ios/actions/new/RemoveDistributionCertificate.ts delete mode 100644 packages/eas-cli/src/credentials/ios/actions/new/RemoveProvisioningProfile.ts delete mode 100644 packages/eas-cli/src/credentials/ios/actions/new/UpdateCredentialsJson.ts diff --git a/packages/eas-cli/src/build/ios/credentials.ts b/packages/eas-cli/src/build/ios/credentials.ts index 191eb97387..b65f3f6fbe 100644 --- a/packages/eas-cli/src/build/ios/credentials.ts +++ b/packages/eas-cli/src/build/ios/credentials.ts @@ -6,7 +6,7 @@ import { createCredentialsContextAsync } from '../../credentials/context'; import IosCredentialsProvider, { IosCredentials, } from '../../credentials/ios/IosCredentialsProvider'; -import { getAppLookupParamsFromContext } from '../../credentials/ios/actions/new/BuildCredentialsUtils'; +import { getAppLookupParamsFromContext } from '../../credentials/ios/actions/BuildCredentialsUtils'; import { AppLookupParams } from '../../credentials/ios/credentials'; import { CredentialsResult } from '../build'; import { BuildContext } from '../context'; diff --git a/packages/eas-cli/src/credentials/credentialsJson/__tests__/update-test.ts b/packages/eas-cli/src/credentials/credentialsJson/__tests__/update-test.ts index 6ba68e98eb..2280ed11c2 100644 --- a/packages/eas-cli/src/credentials/credentialsJson/__tests__/update-test.ts +++ b/packages/eas-cli/src/credentials/credentialsJson/__tests__/update-test.ts @@ -11,7 +11,7 @@ import { testCommonIosAppCredentialsFragment, } from '../../__tests__/fixtures-ios'; import { getNewIosApiMockWithoutCredentials } from '../../__tests__/fixtures-new-ios'; -import { getAppLookupParamsFromContext } from '../../ios/actions/new/BuildCredentialsUtils'; +import { getAppLookupParamsFromContext } from '../../ios/actions/BuildCredentialsUtils'; import { updateAndroidCredentialsAsync, updateIosCredentialsAsync } from '../update'; jest.mock('fs'); diff --git a/packages/eas-cli/src/credentials/ios/__tests__/IosCredentialsProvider-test.ts b/packages/eas-cli/src/credentials/ios/__tests__/IosCredentialsProvider-test.ts index 92ad908191..970e113454 100644 --- a/packages/eas-cli/src/credentials/ios/__tests__/IosCredentialsProvider-test.ts +++ b/packages/eas-cli/src/credentials/ios/__tests__/IosCredentialsProvider-test.ts @@ -7,7 +7,7 @@ import { createCtxMock } from '../../__tests__/fixtures-context'; import { testIosAppCredentialsWithBuildCredentialsQueryResult } from '../../__tests__/fixtures-ios'; import { getNewIosApiMockWithoutCredentials } from '../../__tests__/fixtures-new-ios'; import IosCredentialsProvider from '../IosCredentialsProvider'; -import { getAppLookupParamsFromContext } from '../actions/new/BuildCredentialsUtils'; +import { getAppLookupParamsFromContext } from '../actions/BuildCredentialsUtils'; jest.mock('fs'); jest.mock('../validators/validateProvisioningProfile', () => ({ diff --git a/packages/eas-cli/src/credentials/ios/actions/new/AppleTeamUtils.ts b/packages/eas-cli/src/credentials/ios/actions/AppleTeamUtils.ts similarity index 69% rename from packages/eas-cli/src/credentials/ios/actions/new/AppleTeamUtils.ts rename to packages/eas-cli/src/credentials/ios/actions/AppleTeamUtils.ts index f064081802..fdd69c30e0 100644 --- a/packages/eas-cli/src/credentials/ios/actions/new/AppleTeamUtils.ts +++ b/packages/eas-cli/src/credentials/ios/actions/AppleTeamUtils.ts @@ -1,6 +1,6 @@ -import { AppleTeamFragment } from '../../../../graphql/generated'; -import { Context } from '../../../context'; -import { AppLookupParams } from '../../api/GraphqlClient'; +import { AppleTeamFragment } from '../../../graphql/generated'; +import { Context } from '../../context'; +import { AppLookupParams } from '../api/GraphqlClient'; export async function resolveAppleTeamIfAuthenticatedAsync( ctx: Context, diff --git a/packages/eas-cli/src/credentials/ios/actions/new/BuildCredentialsUtils.ts b/packages/eas-cli/src/credentials/ios/actions/BuildCredentialsUtils.ts similarity index 91% rename from packages/eas-cli/src/credentials/ios/actions/new/BuildCredentialsUtils.ts rename to packages/eas-cli/src/credentials/ios/actions/BuildCredentialsUtils.ts index beffe75f80..bee45de8bd 100644 --- a/packages/eas-cli/src/credentials/ios/actions/new/BuildCredentialsUtils.ts +++ b/packages/eas-cli/src/credentials/ios/actions/BuildCredentialsUtils.ts @@ -6,14 +6,11 @@ import { AppleTeamFragment, IosDistributionType as GraphQLIosDistributionType, IosAppBuildCredentialsFragment, -} from '../../../../graphql/generated'; -import { - getProjectAccountName, - getProjectConfigDescription, -} from '../../../../project/projectUtils'; -import { findAccountByName } from '../../../../user/Account'; -import { Context } from '../../../context'; -import { AppLookupParams } from '../../api/GraphqlClient'; +} from '../../../graphql/generated'; +import { getProjectAccountName, getProjectConfigDescription } from '../../../project/projectUtils'; +import { findAccountByName } from '../../../user/Account'; +import { Context } from '../../context'; +import { AppLookupParams } from '../api/GraphqlClient'; import { resolveAppleTeamIfAuthenticatedAsync } from './AppleTeamUtils'; export async function getAllBuildCredentialsAsync( diff --git a/packages/eas-cli/src/credentials/ios/actions/ConfigureProvisioningProfile.ts b/packages/eas-cli/src/credentials/ios/actions/ConfigureProvisioningProfile.ts index 44cd9d03b7..60ce2f943d 100644 --- a/packages/eas-cli/src/credentials/ios/actions/ConfigureProvisioningProfile.ts +++ b/packages/eas-cli/src/credentials/ios/actions/ConfigureProvisioningProfile.ts @@ -2,91 +2,109 @@ import assert from 'assert'; import chalk from 'chalk'; import ora from 'ora'; +import { + AppleDistributionCertificateFragment, + AppleProvisioningProfileFragment, +} from '../../../graphql/generated'; import Log from '../../../log'; -import { Action, CredentialsManager } from '../../CredentialsManager'; import { Context } from '../../context'; -import { - DistributionCertificate, - ProvisioningProfileStoreInfo, -} from '../appstore/Credentials.types'; -import { AppLookupParams } from '../credentials'; -import { selectProvisioningProfileFromAppleAsync } from './ProvisioningProfileUtils'; - -export class UseExistingProvisioningProfile implements Action { - constructor(private app: AppLookupParams) {} - - public async runAsync(manager: CredentialsManager, ctx: Context): Promise { - const selected = await selectProvisioningProfileFromAppleAsync(ctx, this.app.bundleIdentifier); - if (selected) { - const distCert = await ctx.ios.getDistributionCertificateAsync(this.app); - assert(distCert, 'missing distribution certificate'); +import { AppLookupParams } from '../api/GraphqlClient'; +import { AppleProvisioningProfileMutationResult } from '../api/graphql/mutations/AppleProvisioningProfileMutation'; +import { ProvisioningProfileStoreInfo } from '../appstore/Credentials.types'; +import { AuthCtx } from '../appstore/authenticate'; +import { MissingCredentialsNonInteractiveError } from '../errors'; - await manager.runActionAsync(new ConfigureProvisioningProfile(this.app)); - } - } -} +export class ConfigureProvisioningProfile { + constructor( + private app: AppLookupParams, + private distributionCertificate: AppleDistributionCertificateFragment, + private originalProvisioningProfile: AppleProvisioningProfileFragment + ) {} -export class ConfigureProvisioningProfile implements Action { - constructor(private app: AppLookupParams) {} - - public async runAsync(manager: CredentialsManager, ctx: Context): Promise { - const profile = await ctx.ios.getProvisioningProfileAsync(this.app); - if (!profile) { - throw new Error('No provisioning profile to configure'); + public async runAsync(ctx: Context): Promise { + if (ctx.nonInteractive) { + throw new MissingCredentialsNonInteractiveError( + 'Configuring Provisioning Profiles is only supported in interactive mode.' + ); } - - if (!profile.provisioningProfileId) { - Log.warn("The provisioning profile we have on file cannot be validated on Apple's servers."); - return; + const { developerPortalIdentifier, provisioningProfile } = this.originalProvisioningProfile; + if (!developerPortalIdentifier && !provisioningProfile) { + Log.warn("The provisioning profile we have on file cannot be configured on Apple's servers."); + return null; } - if (ctx.appStore.authCtx) { - const distCert = await ctx.ios.getDistributionCertificateAsync(this.app); - if (!distCert) { - Log.warn('There is no distribution certificate for this app.'); - return; - } - const profilesFromApple = await ctx.appStore.listProvisioningProfilesAsync( - this.app.bundleIdentifier - ); - const profilesWithMatchingId = profilesFromApple.filter( - appleInfo => appleInfo.provisioningProfileId === profile.provisioningProfileId - ); - if (!profilesWithMatchingId || profilesWithMatchingId.length < 1) { - Log.warn('This profile is no longer valid on Apple Developer Portal.'); - } - - await this.configureAndUpdateAsync(ctx, this.app, distCert, profilesWithMatchingId[0]); - } else { + if (!ctx.appStore.authCtx) { Log.warn( "Without access to your Apple account we can't configure provisioning profiles for you." ); Log.warn('Make sure to recreate the profile if you selected a new distribution certificate.'); + return null; + } + + const profilesFromApple = await ctx.appStore.listProvisioningProfilesAsync( + this.app.bundleIdentifier + ); + const [matchingProfile] = profilesFromApple.filter(appleInfo => + developerPortalIdentifier + ? appleInfo.provisioningProfileId === developerPortalIdentifier + : appleInfo.provisioningProfile === provisioningProfile + ); + if (!matchingProfile) { + Log.warn( + `Profile ${ + developerPortalIdentifier ? `${developerPortalIdentifier} ` : '' + }not found on Apple Developer Portal.` + ); + return null; } + + return await this.configureAndUpdateAsync(ctx, ctx.appStore.authCtx, this.app, matchingProfile); } private async configureAndUpdateAsync( ctx: Context, + authCtx: AuthCtx, app: AppLookupParams, - distCert: DistributionCertificate, profileFromApple: ProvisioningProfileStoreInfo - ) { + ): Promise { + const { + developerPortalIdentifier, + certificateP12, + certificatePassword, + serialNumber, + } = this.distributionCertificate; + assert( + certificateP12 && certificatePassword, + 'Distribution Certificate P12 and Password is required' + ); // configure profile on Apple's Server to use our distCert const updatedProfile = await ctx.appStore.useExistingProvisioningProfileAsync( app.bundleIdentifier, profileFromApple, - distCert + { + certId: developerPortalIdentifier ?? undefined, + certP12: certificateP12, + certPassword: certificatePassword, + distCertSerialNumber: serialNumber, + teamId: authCtx.appleId, + } ); const bundleIdTag = `(${app.bundleIdentifier})`; - const slugTag = `@${app.accountName}/${app.projectName}`; + const slugTag = `@${app.account.name}/${app.projectName}`; const projectTag = `${chalk.bold(slugTag)} ${chalk.dim(bundleIdTag)}`; const spinner = ora(`Updating Expo profile for ${projectTag}`).start(); try { - // Update profile on EAS servers - await ctx.ios.updateProvisioningProfileAsync(app, updatedProfile); + const configuredProvisioningProfile = await ctx.newIos.updateProvisioningProfileAsync( + this.originalProvisioningProfile.id, + { + appleProvisioningProfile: updatedProfile.provisioningProfile, + developerPortalIdentifier: updatedProfile.provisioningProfileId, + } + ); spinner.succeed(`Updated Expo profile for ${projectTag}`); + return configuredProvisioningProfile; } catch (error) { spinner.fail(); throw error; diff --git a/packages/eas-cli/src/credentials/ios/actions/CreateDistributionCertificate.ts b/packages/eas-cli/src/credentials/ios/actions/CreateDistributionCertificate.ts index 65f5184f22..17a0eb1124 100644 --- a/packages/eas-cli/src/credentials/ios/actions/CreateDistributionCertificate.ts +++ b/packages/eas-cli/src/credentials/ios/actions/CreateDistributionCertificate.ts @@ -1,41 +1,16 @@ -import assert from 'assert'; - import Log from '../../../log'; -import { Action, CredentialsManager } from '../../CredentialsManager'; +import { Account } from '../../../user/Account'; import { Context } from '../../context'; -import { IosDistCredentials } from '../credentials'; -import { displayIosUserCredentials } from '../utils/printCredentials'; +import { AppleDistributionCertificateMutationResult } from '../api/graphql/mutations/AppleDistributionCertificateMutation'; import { provideOrGenerateDistributionCertificateAsync } from './DistributionCertificateUtils'; -export class CreateDistributionCertificateStandaloneManager implements Action { - constructor(private accountName: string) {} - - public async runAsync(manager: CredentialsManager, ctx: Context): Promise { - const action = new CreateDistributionCertificate(this.accountName); - await manager.runActionAsync(action); - - Log.newLine(); - displayIosUserCredentials(action.distCredentials); - Log.newLine(); - } -} - -export class CreateDistributionCertificate implements Action { - private _distCredentials?: IosDistCredentials; - - constructor(private accountName: string) {} - - public get distCredentials(): IosDistCredentials { - assert(this._distCredentials, 'distCredentials can be accessed only after runAsync'); - return this._distCredentials; - } +export class CreateDistributionCertificate { + constructor(private account: Account) {} - public async runAsync(manager: CredentialsManager, ctx: Context): Promise { - const distCert = await provideOrGenerateDistributionCertificateAsync(ctx, this.accountName); - this._distCredentials = await ctx.ios.createDistributionCertificateAsync( - this.accountName, - distCert - ); + public async runAsync(ctx: Context): Promise { + const distCert = await provideOrGenerateDistributionCertificateAsync(ctx, this.account.name); + const result = await ctx.newIos.createDistributionCertificateAsync(this.account, distCert); Log.succeed('Created distribution certificate'); + return result; } } diff --git a/packages/eas-cli/src/credentials/ios/actions/new/CreateProvisioningProfile.ts b/packages/eas-cli/src/credentials/ios/actions/CreateProvisioningProfile.ts similarity index 77% rename from packages/eas-cli/src/credentials/ios/actions/new/CreateProvisioningProfile.ts rename to packages/eas-cli/src/credentials/ios/actions/CreateProvisioningProfile.ts index 42b555622d..34a4d5b758 100644 --- a/packages/eas-cli/src/credentials/ios/actions/new/CreateProvisioningProfile.ts +++ b/packages/eas-cli/src/credentials/ios/actions/CreateProvisioningProfile.ts @@ -1,18 +1,18 @@ import assert from 'assert'; import nullthrows from 'nullthrows'; -import { AppleDistributionCertificateFragment } from '../../../../graphql/generated'; -import Log from '../../../../log'; -import { Context } from '../../../context'; -import { askForUserProvidedAsync } from '../../../utils/promptForCredentials'; -import { AppLookupParams } from '../../api/GraphqlClient'; -import { AppleProvisioningProfileMutationResult } from '../../api/graphql/mutations/AppleProvisioningProfileMutation'; -import { ProvisioningProfile } from '../../appstore/Credentials.types'; -import { AuthCtx } from '../../appstore/authenticate'; -import { provisioningProfileSchema } from '../../credentials'; -import { MissingCredentialsNonInteractiveError } from '../../errors'; -import { generateProvisioningProfileAsync } from '../ProvisioningProfileUtils'; +import { AppleDistributionCertificateFragment } from '../../../graphql/generated'; +import Log from '../../../log'; +import { Context } from '../../context'; +import { askForUserProvidedAsync } from '../../utils/promptForCredentials'; +import { AppLookupParams } from '../api/GraphqlClient'; +import { AppleProvisioningProfileMutationResult } from '../api/graphql/mutations/AppleProvisioningProfileMutation'; +import { ProvisioningProfile } from '../appstore/Credentials.types'; +import { AuthCtx } from '../appstore/authenticate'; +import { provisioningProfileSchema } from '../credentials'; +import { MissingCredentialsNonInteractiveError } from '../errors'; import { resolveAppleTeamIfAuthenticatedAsync } from './AppleTeamUtils'; +import { generateProvisioningProfileAsync } from './ProvisioningProfileUtils'; export class CreateProvisioningProfile { constructor( diff --git a/packages/eas-cli/src/credentials/ios/actions/new/DeviceUtils.ts b/packages/eas-cli/src/credentials/ios/actions/DeviceUtils.ts similarity index 85% rename from packages/eas-cli/src/credentials/ios/actions/new/DeviceUtils.ts rename to packages/eas-cli/src/credentials/ios/actions/DeviceUtils.ts index 58f437d395..89376d815e 100644 --- a/packages/eas-cli/src/credentials/ios/actions/new/DeviceUtils.ts +++ b/packages/eas-cli/src/credentials/ios/actions/DeviceUtils.ts @@ -1,6 +1,6 @@ -import { AppleDevice, AppleDeviceFragment } from '../../../../graphql/generated'; -import { APPLE_DEVICE_CLASS_LABELS } from '../../../../graphql/types/credentials/AppleDevice'; -import { promptAsync } from '../../.././../prompts'; +import { AppleDevice, AppleDeviceFragment } from '../../../graphql/generated'; +import { APPLE_DEVICE_CLASS_LABELS } from '../../../graphql/types/credentials/AppleDevice'; +import { promptAsync } from '../.././../prompts'; export async function chooseDevices( allDevices: AppleDeviceFragment[], diff --git a/packages/eas-cli/src/credentials/ios/actions/DistributionCertificateUtils.ts b/packages/eas-cli/src/credentials/ios/actions/DistributionCertificateUtils.ts index 341c322cd8..07c30d03e0 100644 --- a/packages/eas-cli/src/credentials/ios/actions/DistributionCertificateUtils.ts +++ b/packages/eas-cli/src/credentials/ios/actions/DistributionCertificateUtils.ts @@ -1,26 +1,154 @@ +import assert from 'assert'; import chalk from 'chalk'; +import dateformat from 'dateformat'; +import { + AppleDistributionCertificateFragment, + AppleTeamFragment, +} from '../../../graphql/generated'; import Log, { learnMore } from '../../../log'; import { promptAsync } from '../../../prompts'; +import { Account } from '../../../user/Account'; +import { fromNow } from '../../../utils/date'; import { Context } from '../../context'; import { askForUserProvidedAsync } from '../../utils/promptForCredentials'; +import { AppLookupParams } from '../api/GraphqlClient'; import { AppleTooManyCertsError } from '../appstore/AppStoreApi'; import { DistributionCertificate, DistributionCertificateStoreInfo, } from '../appstore/Credentials.types'; -import { - filterRevokedDistributionCerts, - sortCertificatesByExpiryDesc, -} from '../appstore/CredentialsUtils'; -import { - IosAppCredentials, - IosDistCredentials, - distributionCertificateSchema, -} from '../credentials'; -import { findP12CertSerialNumber } from '../utils/p12Certificate'; +import { filterRevokedDistributionCerts } from '../appstore/CredentialsUtilsBeta'; +import { distributionCertificateSchema } from '../credentials'; import { validateDistributionCertificateAsync } from '../validators/validateDistributionCertificate'; +export function formatDistributionCertificate( + distributionCertificate: AppleDistributionCertificateFragment, + validSerialNumbers?: string[] +): string { + const { + serialNumber, + developerPortalIdentifier, + appleTeam, + validityNotBefore, + validityNotAfter, + updatedAt, + } = distributionCertificate; + let line: string = ''; + if (developerPortalIdentifier) { + line += `Cert ID: ${developerPortalIdentifier}`; + } + line += `${line === '' ? '' : ', '}Serial number: ${serialNumber}${ + appleTeam ? `, ${formatAppleTeam(appleTeam)}` : '' + }`; + line += chalk.gray( + `\n Created: ${fromNow(new Date(validityNotBefore))} ago, Updated: ${fromNow( + new Date(updatedAt) + )} ago,` + ); + line += chalk.gray(`\n Expires: ${dateformat(validityNotAfter, 'expiresHeaderFormat')}`); + const apps = distributionCertificate.iosAppBuildCredentialsList.map( + buildCredentials => buildCredentials.iosAppCredentials.app + ); + if (apps.length) { + const appFullNames = apps.map(app => app.fullName).join(','); + line += chalk.gray(`\n 📲 Used by: ${appFullNames}`); + } + + if (validSerialNumbers?.includes(serialNumber)) { + line += chalk.gray("\n ✅ Currently valid on Apple's servers."); + } else { + line += ''; + } + return line; +} + +function formatAppleTeam({ appleTeamIdentifier, appleTeamName }: AppleTeamFragment): string { + return `Team ID: ${appleTeamIdentifier}${appleTeamName ? `, Team name: ${appleTeamName}` : ''}`; +} + +async function _selectDistributionCertificateAsync( + distCerts: AppleDistributionCertificateFragment[], + validDistributionCertificates?: AppleDistributionCertificateFragment[] +): Promise { + const validDistCertSerialNumbers = validDistributionCertificates?.map( + distCert => distCert.serialNumber + ); + const { chosenDistCert } = await promptAsync({ + type: 'select', + name: 'chosenDistCert', + message: 'Select certificate from the list.', + choices: distCerts.map(distCert => ({ + title: formatDistributionCertificate(distCert, validDistCertSerialNumbers), + value: distCert, + })), + }); + return chosenDistCert; +} + +/** + * select a distribution certificate from an account (validity status shown on a best effort basis) + * */ +export async function selectDistributionCertificateWithDependenciesAsync( + ctx: Context, + account: Account +): Promise { + const distCertsForAccount = await ctx.newIos.getDistributionCertificatesForAccountAsync(account); + if (distCertsForAccount.length === 0) { + Log.warn(`There are no Distribution Certificates available in your EAS account.`); + return null; + } + if (!ctx.appStore.authCtx) { + return _selectDistributionCertificateAsync(distCertsForAccount); + } + + // get valid certs on the developer portal + const certInfoFromApple = await ctx.appStore.listDistributionCertificatesAsync(); + const validDistCerts = await filterRevokedDistributionCerts( + distCertsForAccount, + certInfoFromApple + ); + + return _selectDistributionCertificateAsync(distCertsForAccount, validDistCerts); +} + +/** + * select a distribution certificate from a valid set (curated on a best effort basis) + * */ +export async function selectValidDistributionCertificateAsync( + ctx: Context, + appLookupParams: AppLookupParams +): Promise { + const distCertsForAccount = await ctx.newIos.getDistributionCertificatesForAccountAsync( + appLookupParams.account + ); + if (distCertsForAccount.length === 0) { + Log.warn(`There are no Distribution Certificates available in your EAS account.`); + return null; + } + if (!ctx.appStore.authCtx) { + return _selectDistributionCertificateAsync(distCertsForAccount); + } + + // filter by apple team + assert(ctx.appStore.authCtx, 'authentication to the Apple App Store is required'); + const appleTeamIdentifier = ctx.appStore.authCtx.team.id; + const distCertsForAppleTeam = distCertsForAccount.filter(distCert => { + return !distCert.appleTeam || distCert.appleTeam.appleTeamIdentifier === appleTeamIdentifier; + }); + + // filter by valid certs on the developer portal + const certInfoFromApple = await ctx.appStore.listDistributionCertificatesAsync(); + const validDistCerts = await filterRevokedDistributionCerts( + distCertsForAppleTeam, + certInfoFromApple + ); + Log.log( + `${validDistCerts.length}/${distCertsForAccount.length} Distribution Certificates are currently valid for Apple Team ${ctx.appStore.authCtx?.team.id}.` + ); + return _selectDistributionCertificateAsync(validDistCerts); +} + const APPLE_DIST_CERTS_TOO_MANY_GENERATED_ERROR = ` You can have only ${chalk.underline( 'three' @@ -125,100 +253,6 @@ async function generateDistributionCertificateAsync( return await generateDistributionCertificateAsync(ctx, accountName); } -interface SelectOptions { - filterInvalid?: boolean; -} -type ValidityStatus = 'UNKNOWN' | 'VALID' | 'INVALID'; - -export async function selectDistributionCertificateAsync( - ctx: Context, - accountName: string, - options: SelectOptions = {} -): Promise { - const credentials = await ctx.ios.getAllCredentialsAsync(accountName); - let distCredentials = credentials.userCredentials.filter( - (cred): cred is IosDistCredentials => cred.type === 'dist-cert' - ); - let validDistCredentials: IosDistCredentials[] | null = null; - if (ctx.appStore.authCtx) { - const certInfoFromApple = await ctx.appStore.listDistributionCertificatesAsync(); - validDistCredentials = filterRevokedDistributionCerts(distCredentials, certInfoFromApple); - } - distCredentials = - options.filterInvalid && validDistCredentials ? validDistCredentials : distCredentials; - - if (distCredentials.length === 0) { - Log.warn('There are no Distribution Certificates available in your Expo account.'); - return null; - } - - const format = (distCredentials: IosDistCredentials): string => { - const usedByApps = credentials.appCredentials.filter( - cred => cred.distCredentialsId === distCredentials.id - ); - let validityStatus: ValidityStatus; - if (!validDistCredentials) { - validityStatus = 'UNKNOWN'; - } else if (validDistCredentials.includes(distCredentials)) { - validityStatus = 'VALID'; - } else { - validityStatus = 'INVALID'; - } - return formatDistributionCertificate(distCredentials, usedByApps, validityStatus); - }; - - const { credentialsIndex } = await promptAsync({ - type: 'select', - name: 'credentialsIndex', - message: 'Select certificate from the list.', - choices: distCredentials.map((entry, index) => ({ - title: format(entry), - value: index, - })), - }); - return distCredentials[credentialsIndex]; -} - -export function formatDistributionCertificate( - distributionCertificate: IosDistCredentials, - usedByApps: IosAppCredentials[], - validityStatus: ValidityStatus = 'UNKNOWN' -): string { - const joinApps = usedByApps.map(i => `${i.experienceName} (${i.bundleIdentifier})`).join(', '); - - const usedByString = joinApps - ? `\n ${chalk.gray(`used by ${joinApps}`)}` - : `\n ${chalk.gray(`not used by any apps`)}`; - - let serialNumber = distributionCertificate.distCertSerialNumber; - try { - if (!serialNumber) { - serialNumber = findP12CertSerialNumber( - distributionCertificate.certP12, - distributionCertificate.certPassword - ); - } - } catch (error) { - serialNumber = chalk.red('invalid serial number'); - } - - let validityText; - if (validityStatus === 'VALID') { - validityText = chalk.gray("\n ✅ Currently valid on Apple's servers."); - } else if (validityStatus === 'INVALID') { - validityText = chalk.gray("\n ❌ No longer valid on Apple's servers."); - } else { - validityText = chalk.gray( - "\n ❓ Validity of this certificate on Apple's servers is unknown." - ); - } - return `Distribution Certificate (Cert ID: ${ - distributionCertificate.certId || '-----' - }, Serial number: ${serialNumber}, Team ID: ${ - distributionCertificate.teamId - })${usedByString}${validityText}`; -} - function formatDistributionCertificateFromApple( appleInfo: DistributionCertificateStoreInfo ): string { @@ -228,20 +262,3 @@ function formatDistributionCertificateFromApple( return `${name} (${status}) - Cert ID: ${id}, Serial number: ${serialNumber}, Team ID: ${appleInfo.ownerId}, Team name: ${ownerName} expires: ${expiresDate}, created: ${createdDate}`; } - -export async function getValidDistCertsAsync( - ctx: Context, - accountName: string -): Promise { - const credentials = await ctx.ios.getAllCredentialsAsync(accountName); - const distCredentials = credentials.userCredentials.filter( - (cred): cred is IosDistCredentials => cred.type === 'dist-cert' - ); - if (!ctx.appStore.authCtx) { - Log.log(chalk.yellow(`Unable to determine validity of Distribution Certificates.`)); - return distCredentials; - } - const certInfoFromApple = await ctx.appStore.listDistributionCertificatesAsync(); - const validCerts = await filterRevokedDistributionCerts(distCredentials, certInfoFromApple); - return sortCertificatesByExpiryDesc(certInfoFromApple, validCerts); -} diff --git a/packages/eas-cli/src/credentials/ios/actions/ProvisioningProfileUtils.ts b/packages/eas-cli/src/credentials/ios/actions/ProvisioningProfileUtils.ts index f8334974ed..18c09c1d5a 100644 --- a/packages/eas-cli/src/credentials/ios/actions/ProvisioningProfileUtils.ts +++ b/packages/eas-cli/src/credentials/ios/actions/ProvisioningProfileUtils.ts @@ -1,38 +1,11 @@ import chalk from 'chalk'; -import Log from '../../../log'; -import { promptAsync } from '../../../prompts'; import { Context } from '../../context'; import { DistributionCertificate, ProvisioningProfile, ProvisioningProfileStoreInfo, } from '../appstore/Credentials.types'; -import { IosAppCredentials } from '../credentials'; - -export async function selectProvisioningProfileFromAppleAsync( - ctx: Context, - bundleIdentifier: string -): Promise { - const profiles = await ctx.appStore.listProvisioningProfilesAsync(bundleIdentifier); - if (profiles.length === 0) { - Log.warn( - `There are no provisioning profiles available on Apple Developer Portal for bundle identifier ${bundleIdentifier}.` - ); - return null; - } - - const { credentialsIndex } = await promptAsync({ - type: 'select', - name: 'credentialsIndex', - message: 'Select provisioning profile from the list.', - choices: profiles.map((entry, index) => ({ - title: formatProvisioningProfileFromApple(entry), - value: index, - })), - }); - return profiles[credentialsIndex]; -} export function formatProvisioningProfileFromApple( appleInfo: ProvisioningProfileStoreInfo @@ -45,36 +18,6 @@ export function formatProvisioningProfileFromApple( return `Provisioning Profile - ID: ${id}${details}`; } -export async function selectProvisioningProfileFromExpoAsync( - ctx: Context, - accountName: string -): Promise { - const profiles = (await ctx.ios.getAllCredentialsAsync(accountName)).appCredentials.filter( - ({ credentials }) => !!credentials.provisioningProfile && !!credentials.provisioningProfileId - ); - if (profiles.length === 0) { - Log.warn('There are no provisioning profiles available in your Expo account.'); - return null; - } - - const format = (profile: IosAppCredentials) => { - const id = chalk.green(profile.credentials.provisioningProfileId || '-----'); - const teamId = profile.credentials.teamId || '------'; - return `Provisioning Profile (ID: ${id}, Team ID: ${teamId})`; - }; - - const { credentialsIndex } = await promptAsync({ - type: 'select', - name: 'credentialsIndex', - message: 'Select provisioning profile from the list.', - choices: profiles.map((entry, index) => ({ - title: format(entry), - value: index, - })), - }); - return profiles[credentialsIndex]; -} - export async function generateProvisioningProfileAsync( ctx: Context, bundleIdentifier: string, diff --git a/packages/eas-cli/src/credentials/ios/actions/RemoveDistributionCertificate.ts b/packages/eas-cli/src/credentials/ios/actions/RemoveDistributionCertificate.ts index 541d0d9e98..7b9c6f7a07 100644 --- a/packages/eas-cli/src/credentials/ios/actions/RemoveDistributionCertificate.ts +++ b/packages/eas-cli/src/credentials/ios/actions/RemoveDistributionCertificate.ts @@ -1,57 +1,47 @@ -import chalk from 'chalk'; - +import { + AppleDistributionCertificateFragment, + AppleProvisioningProfileIdentifiersFragment, +} from '../../../graphql/generated'; import Log from '../../../log'; import { confirmAsync } from '../../../prompts'; -import { Action, CredentialsManager } from '../../CredentialsManager'; +import { Account } from '../../../user/Account'; import { Context } from '../../context'; -import { IosAppCredentials, getAppLookupParams } from '../credentials'; -import { selectDistributionCertificateAsync } from './DistributionCertificateUtils'; -import { RemoveSpecificProvisioningProfile } from './RemoveProvisioningProfile'; - -interface RemoveOptions { - shouldRevoke?: boolean; -} +import { AppLookupParams } from '../api/GraphqlClient'; +import { selectDistributionCertificateWithDependenciesAsync } from './DistributionCertificateUtils'; +import { RemoveProvisioningProfiles } from './RemoveProvisioningProfile'; -export class RemoveDistributionCertificate implements Action { - constructor(private accountName: string, private options: RemoveOptions = {}) {} +export class SelectAndRemoveDistributionCertificate { + constructor(private account: Account) {} - async runAsync(manager: CredentialsManager, ctx: Context): Promise { - const selected = await selectDistributionCertificateAsync(ctx, this.accountName); - if (selected?.id) { - await manager.runActionAsync( - new RemoveSpecificDistributionCertificate(selected?.id, this.accountName, this.options) - ); + async runAsync(ctx: Context): Promise { + const selected = await selectDistributionCertificateWithDependenciesAsync(ctx, this.account); + if (selected) { + await new RemoveDistributionCertificate(this.account, selected).runAsync(ctx); Log.succeed('Removed distribution certificate'); Log.newLine(); } } } -interface RemoveSpecificOptions { - shouldRevoke?: boolean; -} - -export class RemoveSpecificDistributionCertificate implements Action { +export class RemoveDistributionCertificate { constructor( - private userCredentialsId: number | string, - private accountName: string, - private options: RemoveSpecificOptions = {} + private account: Account, + private distributionCertificate: AppleDistributionCertificateFragment ) {} - public async runAsync(manager: CredentialsManager, ctx: Context): Promise { - const distributionCertificate = await ctx.ios.getDistributionCertificateByIdAsync( - this.userCredentialsId, - this.accountName - ); - const credentials = await ctx.ios.getAllCredentialsAsync(this.accountName); - const apps = credentials.appCredentials.filter( - cred => cred.distCredentialsId === this.userCredentialsId + public async runAsync(ctx: Context): Promise { + const apps = this.distributionCertificate.iosAppBuildCredentialsList.map( + buildCredentials => buildCredentials.iosAppCredentials.app ); - const appList = apps.map(appCred => chalk.green(appCred.experienceName)).join(', '); - - if (appList && !ctx.nonInteractive) { + if (apps.length !== 0) { + const appFullNames = apps.map(app => app.fullName).join(','); + if (ctx.nonInteractive) { + throw new Error( + `Certificate is currently used by ${appFullNames} and cannot be deleted in non-interactive mode.` + ); + } const confirm = await confirmAsync({ - message: `You are removing certificate used by ${appList}. Do you want to continue?`, + message: `You are removing certificate used by ${appFullNames}. Do you want to continue?`, }); if (!confirm) { Log.log('Aborting'); @@ -60,43 +50,41 @@ export class RemoveSpecificDistributionCertificate implements Action { } Log.log('Removing Distribution Certificate'); - await ctx.ios.deleteDistributionCertificateAsync(this.userCredentialsId, this.accountName); + await ctx.newIos.deleteDistributionCertificateAsync(this.distributionCertificate.id); - let shouldRevoke = this.options.shouldRevoke; - if (distributionCertificate.certId) { - if (!shouldRevoke && !ctx.nonInteractive) { + if (this.distributionCertificate.developerPortalIdentifier) { + let shouldRevoke = false; + if (!ctx.nonInteractive) { shouldRevoke = await confirmAsync({ message: `Do you also want to revoke this Distribution Certificate on Apple Developer Portal?`, }); + } else if (ctx.nonInteractive) { + Log.log('Skipping certificate revocation on the Apple Developer Portal.'); } if (shouldRevoke) { - await ctx.appStore.revokeDistributionCertificateAsync([distributionCertificate.certId]); + await ctx.appStore.revokeDistributionCertificateAsync([ + this.distributionCertificate.developerPortalIdentifier, + ]); } } - await this.removeInvalidProvisioningProfilesAsync(manager, ctx, apps, shouldRevoke); + await this.removeInvalidProvisioningProfilesAsync(ctx); } - private async removeInvalidProvisioningProfilesAsync( - manager: CredentialsManager, - ctx: Context, - apps: IosAppCredentials[], - shouldRevoke?: boolean - ) { - for (const appCredentials of apps) { - const appLookupParams = getAppLookupParams( - appCredentials.experienceName, - appCredentials.bundleIdentifier - ); - if (!(await ctx.ios.getProvisioningProfileAsync(appLookupParams))) { - continue; + private async removeInvalidProvisioningProfilesAsync(ctx: Context): Promise { + const buildCredentialsList = this.distributionCertificate.iosAppBuildCredentialsList; + const appsWithProfilesToRemove: AppLookupParams[] = []; + const profilesToRemove: AppleProvisioningProfileIdentifiersFragment[] = []; + for (const buildCredentials of buildCredentialsList) { + const projectName = buildCredentials.iosAppCredentials.app.slug; + const { bundleIdentifier } = buildCredentials.iosAppCredentials.appleAppIdentifier; + const appLookupParams = { account: this.account, projectName, bundleIdentifier }; + const maybeProvisioningProfile = buildCredentials.provisioningProfile; + if (maybeProvisioningProfile) { + appsWithProfilesToRemove.push(appLookupParams); + profilesToRemove.push(maybeProvisioningProfile); } - Log.log( - `Removing Provisioning Profile for ${appCredentials.experienceName} (${appCredentials.bundleIdentifier})` - ); - await manager.runActionAsync( - new RemoveSpecificProvisioningProfile(appLookupParams, { shouldRevoke }) - ); } + await new RemoveProvisioningProfiles(appsWithProfilesToRemove, profilesToRemove).runAsync(ctx); } } diff --git a/packages/eas-cli/src/credentials/ios/actions/RemoveProvisioningProfile.ts b/packages/eas-cli/src/credentials/ios/actions/RemoveProvisioningProfile.ts index f62b9ca356..1fb8f3c0a4 100644 --- a/packages/eas-cli/src/credentials/ios/actions/RemoveProvisioningProfile.ts +++ b/packages/eas-cli/src/credentials/ios/actions/RemoveProvisioningProfile.ts @@ -1,48 +1,32 @@ +import { assert } from '@expo/config'; + +import { AppleProvisioningProfileIdentifiersFragment } from '../../../graphql/generated'; import Log from '../../../log'; -import { confirmAsync } from '../../../prompts'; -import { Action, CredentialsManager } from '../../CredentialsManager'; import { Context } from '../../context'; -import { AppLookupParams, getAppLookupParams } from '../credentials'; -import { selectProvisioningProfileFromExpoAsync } from './ProvisioningProfileUtils'; - -interface RemoveOptions { - shouldRevoke?: boolean; -} - -export class RemoveProvisioningProfile implements Action { - constructor(private accountName: string, private options: RemoveOptions = {}) {} - - async runAsync(manager: CredentialsManager, ctx: Context): Promise { - const selected = await selectProvisioningProfileFromExpoAsync(ctx, this.accountName); - if (selected) { - const app = getAppLookupParams(selected.experienceName, selected.bundleIdentifier); - await manager.runActionAsync(new RemoveSpecificProvisioningProfile(app, this.options)); - } - } -} - -interface RemoveSpecificOptions { - shouldRevoke?: boolean; -} - -export class RemoveSpecificProvisioningProfile implements Action { - constructor(private app: AppLookupParams, private options: RemoveSpecificOptions = {}) {} - - async runAsync(manager: CredentialsManager, ctx: Context): Promise { - await ctx.ios.deleteProvisioningProfileAsync(this.app); - Log.succeed( - `Removed provisioning profile for @${this.app.accountName}/${this.app.projectName} (${this.app.bundleIdentifier})` +import { AppLookupParams } from '../api/GraphqlClient'; + +export class RemoveProvisioningProfiles { + constructor( + private apps: AppLookupParams[], + private provisioningProfiles: AppleProvisioningProfileIdentifiersFragment[] + ) { + assert( + apps.length === provisioningProfiles.length, + 'apps must correspond to the provisioning profiles being removed' ); + } - let { shouldRevoke } = this.options; - if (!shouldRevoke && !ctx.nonInteractive) { - shouldRevoke = await confirmAsync({ - message: 'Do you also want to revoke this provisioning profile on Apple Developer Portal?', - }); - } - - if (shouldRevoke) { - await ctx.appStore.revokeProvisioningProfileAsync(this.app.bundleIdentifier); + async runAsync(ctx: Context): Promise { + if (this.provisioningProfiles.length === 0) { + Log.log(`Skipping deletion of Provisioning Profiles`); + return; } + await ctx.newIos.deleteProvisioningProfilesAsync( + this.provisioningProfiles.map(profile => profile.id) + ); + const appAndBundles = this.apps + .map(app => `@${app.account.name}/${app.projectName} (${app.bundleIdentifier})`) + .join(','); + Log.succeed(`Successfully removed provisioning profiles for ${appAndBundles}`); } } diff --git a/packages/eas-cli/src/credentials/ios/actions/new/SetupAdhocProvisioningProfile.ts b/packages/eas-cli/src/credentials/ios/actions/SetupAdhocProvisioningProfile.ts similarity index 95% rename from packages/eas-cli/src/credentials/ios/actions/new/SetupAdhocProvisioningProfile.ts rename to packages/eas-cli/src/credentials/ios/actions/SetupAdhocProvisioningProfile.ts index d4b4b103af..466d8032e7 100644 --- a/packages/eas-cli/src/credentials/ios/actions/new/SetupAdhocProvisioningProfile.ts +++ b/packages/eas-cli/src/credentials/ios/actions/SetupAdhocProvisioningProfile.ts @@ -4,7 +4,7 @@ import differenceBy from 'lodash/differenceBy'; import isEqual from 'lodash/isEqual'; import nullthrows from 'nullthrows'; -import DeviceCreateAction, { RegistrationMethod } from '../../../../devices/actions/create/action'; +import DeviceCreateAction, { RegistrationMethod } from '../../../devices/actions/create/action'; import { AppleDeviceFragment, AppleDistributionCertificateFragment, @@ -12,13 +12,13 @@ import { AppleTeamFragment, IosAppBuildCredentialsFragment, IosDistributionType, -} from '../../../../graphql/generated'; -import Log from '../../../../log'; -import { confirmAsync, pressAnyKeyToContinueAsync } from '../../../../prompts'; -import { Context } from '../../../context'; -import { AppLookupParams } from '../../api/GraphqlClient'; -import { MissingCredentialsNonInteractiveError } from '../../errors'; -import { validateProvisioningProfileAsync } from '../../validators/validateProvisioningProfile'; +} from '../../../graphql/generated'; +import Log from '../../../log'; +import { confirmAsync, pressAnyKeyToContinueAsync } from '../../../prompts'; +import { Context } from '../../context'; +import { AppLookupParams } from '../api/GraphqlClient'; +import { MissingCredentialsNonInteractiveError } from '../errors'; +import { validateProvisioningProfileAsync } from '../validators/validateProvisioningProfile'; import { resolveAppleTeamIfAuthenticatedAsync } from './AppleTeamUtils'; import { assignBuildCredentialsAsync, getBuildCredentialsAsync } from './BuildCredentialsUtils'; import { chooseDevices, formatDeviceLabel } from './DeviceUtils'; diff --git a/packages/eas-cli/src/credentials/ios/actions/SetupBuildCredentials.ts b/packages/eas-cli/src/credentials/ios/actions/SetupBuildCredentials.ts index a787f5f789..0c549184b5 100644 --- a/packages/eas-cli/src/credentials/ios/actions/SetupBuildCredentials.ts +++ b/packages/eas-cli/src/credentials/ios/actions/SetupBuildCredentials.ts @@ -7,18 +7,13 @@ import { IosAppBuildCredentialsFragment, } from '../../../graphql/generated'; import Log from '../../../log'; -import { promptAsync } from '../../../prompts'; import { Action, CredentialsManager } from '../../CredentialsManager'; import { Context } from '../../context'; -import { isCredentialsMap, readIosCredentialsAsync } from '../../credentialsJson/read'; import { AppLookupParams as GraphQLAppLookupParams } from '../api/GraphqlClient'; -import { AppLookupParams, IosAppCredentials } from '../credentials'; -import { displayProjectCredentials as legacyDisplayProjectCredentials } from '../utils/printCredentials'; import { displayProjectCredentials } from '../utils/printCredentialsBeta'; -import { readAppleTeam } from '../utils/provisioningProfile'; -import { SetupAdhocProvisioningProfile } from './new/SetupAdhocProvisioningProfile'; -import { SetupInternalProvisioningProfile } from './new/SetupInternalProvisioningProfile'; -import { SetupProvisioningProfile } from './new/SetupProvisioningProfile'; +import { SetupAdhocProvisioningProfile } from './SetupAdhocProvisioningProfile'; +import { SetupInternalProvisioningProfile } from './SetupInternalProvisioningProfile'; +import { SetupProvisioningProfile } from './SetupProvisioningProfile'; interface Options { app: GraphQLAppLookupParams; @@ -97,94 +92,3 @@ export class SetupBuildCredentials implements Action { } } } - -export class SetupBuildCredentialsFromCredentialsJson implements Action { - constructor(private app: AppLookupParams) {} - - async runAsync(manager: CredentialsManager, ctx: Context): Promise { - let localCredentials; - try { - localCredentials = await readIosCredentialsAsync(ctx.projectDir); - } catch (error) { - Log.error( - 'Reading credentials from credentials.json failed. Make sure this file is correct and all credentials are present there.' - ); - throw error; - } - - // TODO: implement storing multi-target credentials on EAS servers - if (isCredentialsMap(localCredentials)) { - throw new Error( - 'Storing multi-target iOS credentials from credentials.json on EAS servers is not yet supported.' - ); - } - - const team = readAppleTeam(localCredentials.provisioningProfile); - await ctx.ios.updateProvisioningProfileAsync(this.app, { - ...team, - provisioningProfile: localCredentials.provisioningProfile, - }); - const credentials = await ctx.ios.getAllCredentialsAsync(this.app.accountName); - const distCert = await ctx.ios.getDistributionCertificateAsync(this.app); - const appsUsingCert = distCert?.id - ? (credentials.appCredentials || []).filter( - (cred: IosAppCredentials) => cred.distCredentialsId === distCert.id - ) - : []; - - const appInfo = `@${this.app.accountName}/${this.app.projectName} (${this.app.bundleIdentifier})`; - const newDistCert = { - ...team, - certP12: localCredentials.distributionCertificate.certP12, - certPassword: localCredentials.distributionCertificate.certPassword, - }; - - if (appsUsingCert.length > 1 && distCert?.id) { - const { update } = await promptAsync({ - type: 'select', - name: 'update', - message: - 'Current distribution certificate is used by multiple apps. Do you want to update all of them?', - choices: [ - { title: 'Update all apps', value: 'all' }, - { title: `Update only ${appInfo}`, value: 'app' }, - ], - }); - if (update === 'all') { - await ctx.ios.updateDistributionCertificateAsync( - distCert.id, - this.app.accountName, - newDistCert - ); - } else { - const createdDistCert = await ctx.ios.createDistributionCertificateAsync( - this.app.accountName, - newDistCert - ); - await ctx.ios.useDistributionCertificateAsync(this.app, createdDistCert.id); - } - } else if (distCert?.id) { - await ctx.ios.updateDistributionCertificateAsync( - distCert.id, - this.app.accountName, - newDistCert - ); - } else { - const createdDistCert = await ctx.ios.createDistributionCertificateAsync( - this.app.accountName, - newDistCert - ); - await ctx.ios.useDistributionCertificateAsync(this.app, createdDistCert.id); - } - - legacyDisplayProjectCredentials( - this.app, - await ctx.ios.getAppCredentialsAsync(this.app), - undefined, - await ctx.ios.getDistributionCertificateAsync(this.app) - ); - Log.newLine(); - Log.log(chalk.green(`All credentials are ready to build ${appInfo}`)); - Log.newLine(); - } -} diff --git a/packages/eas-cli/src/credentials/ios/actions/new/SetupBuildCredentialsFromCredentialsJson.ts b/packages/eas-cli/src/credentials/ios/actions/SetupBuildCredentialsFromCredentialsJson.ts similarity index 94% rename from packages/eas-cli/src/credentials/ios/actions/new/SetupBuildCredentialsFromCredentialsJson.ts rename to packages/eas-cli/src/credentials/ios/actions/SetupBuildCredentialsFromCredentialsJson.ts index c9d9acf4e6..5b7bb87d55 100644 --- a/packages/eas-cli/src/credentials/ios/actions/new/SetupBuildCredentialsFromCredentialsJson.ts +++ b/packages/eas-cli/src/credentials/ios/actions/SetupBuildCredentialsFromCredentialsJson.ts @@ -7,18 +7,18 @@ import { AppleTeamFragment, IosAppBuildCredentialsFragment, IosDistributionType, -} from '../../../../graphql/generated'; -import Log from '../../../../log'; -import { confirmAsync } from '../../../../prompts'; -import { Context } from '../../../context'; +} from '../../../graphql/generated'; +import Log from '../../../log'; +import { confirmAsync } from '../../../prompts'; +import { Context } from '../../context'; import { IosTargetCredentials, isCredentialsMap, readIosCredentialsAsync, -} from '../../../credentialsJson/read'; -import { AppLookupParams } from '../../api/GraphqlClient'; -import { displayProjectCredentials } from '../../utils/printCredentialsBeta'; -import { readAppleTeam } from '../../utils/provisioningProfile'; +} from '../../credentialsJson/read'; +import { AppLookupParams } from '../api/GraphqlClient'; +import { displayProjectCredentials } from '../utils/printCredentialsBeta'; +import { readAppleTeam } from '../utils/provisioningProfile'; import { assignBuildCredentialsAsync, getBuildCredentialsAsync, diff --git a/packages/eas-cli/src/credentials/ios/actions/new/SetupDistributionCertificate.ts b/packages/eas-cli/src/credentials/ios/actions/SetupDistributionCertificate.ts similarity index 92% rename from packages/eas-cli/src/credentials/ios/actions/new/SetupDistributionCertificate.ts rename to packages/eas-cli/src/credentials/ios/actions/SetupDistributionCertificate.ts index 7bc90b98ca..e670163a49 100644 --- a/packages/eas-cli/src/credentials/ios/actions/new/SetupDistributionCertificate.ts +++ b/packages/eas-cli/src/credentials/ios/actions/SetupDistributionCertificate.ts @@ -5,14 +5,14 @@ import { AppleDistributionCertificate, AppleDistributionCertificateFragment, IosDistributionType, -} from '../../../../graphql/generated'; -import Log from '../../../../log'; -import { confirmAsync, promptAsync } from '../../../../prompts'; -import { Context } from '../../../context'; -import { AppLookupParams } from '../../api/GraphqlClient'; -import { AppleDistributionCertificateMutationResult } from '../../api/graphql/mutations/AppleDistributionCertificateMutation'; -import { getValidCertSerialNumbers } from '../../appstore/CredentialsUtils'; -import { AppleTeamMissingError, MissingCredentialsNonInteractiveError } from '../../errors'; +} from '../../../graphql/generated'; +import Log from '../../../log'; +import { confirmAsync, promptAsync } from '../../../prompts'; +import { Context } from '../../context'; +import { AppLookupParams } from '../api/GraphqlClient'; +import { AppleDistributionCertificateMutationResult } from '../api/graphql/mutations/AppleDistributionCertificateMutation'; +import { getValidCertSerialNumbers } from '../appstore/CredentialsUtils'; +import { AppleTeamMissingError, MissingCredentialsNonInteractiveError } from '../errors'; import { resolveAppleTeamIfAuthenticatedAsync } from './AppleTeamUtils'; import { CreateDistributionCertificate } from './CreateDistributionCertificate'; import { formatDistributionCertificate } from './DistributionCertificateUtils'; diff --git a/packages/eas-cli/src/credentials/ios/actions/new/SetupInternalProvisioningProfile.ts b/packages/eas-cli/src/credentials/ios/actions/SetupInternalProvisioningProfile.ts similarity index 95% rename from packages/eas-cli/src/credentials/ios/actions/new/SetupInternalProvisioningProfile.ts rename to packages/eas-cli/src/credentials/ios/actions/SetupInternalProvisioningProfile.ts index 301599a4b0..a94e151618 100644 --- a/packages/eas-cli/src/credentials/ios/actions/new/SetupInternalProvisioningProfile.ts +++ b/packages/eas-cli/src/credentials/ios/actions/SetupInternalProvisioningProfile.ts @@ -1,8 +1,8 @@ -import { IosAppBuildCredentialsFragment, IosDistributionType } from '../../../../graphql/generated'; -import Log from '../../../../log'; -import { promptAsync } from '../../../../prompts'; -import { Context } from '../../../context'; -import { AppLookupParams } from '../../api/GraphqlClient'; +import { IosAppBuildCredentialsFragment, IosDistributionType } from '../../../graphql/generated'; +import Log from '../../../log'; +import { promptAsync } from '../../../prompts'; +import { Context } from '../../context'; +import { AppLookupParams } from '../api/GraphqlClient'; import { getAllBuildCredentialsAsync } from './BuildCredentialsUtils'; import { SetupAdhocProvisioningProfile } from './SetupAdhocProvisioningProfile'; import { SetupProvisioningProfile } from './SetupProvisioningProfile'; diff --git a/packages/eas-cli/src/credentials/ios/actions/new/SetupProvisioningProfile.ts b/packages/eas-cli/src/credentials/ios/actions/SetupProvisioningProfile.ts similarity index 90% rename from packages/eas-cli/src/credentials/ios/actions/new/SetupProvisioningProfile.ts rename to packages/eas-cli/src/credentials/ios/actions/SetupProvisioningProfile.ts index 80b772c4de..9c6ce44867 100644 --- a/packages/eas-cli/src/credentials/ios/actions/new/SetupProvisioningProfile.ts +++ b/packages/eas-cli/src/credentials/ios/actions/SetupProvisioningProfile.ts @@ -5,14 +5,13 @@ import { AppleProvisioningProfileFragment, IosAppBuildCredentialsFragment, IosDistributionType, -} from '../../../../graphql/generated'; -import { confirmAsync } from '../../../../prompts'; -import { Context } from '../../../context'; -import { AppLookupParams } from '../../api/GraphqlClient'; -import { ProvisioningProfileStoreInfo } from '../../appstore/Credentials.types'; -import { MissingCredentialsNonInteractiveError } from '../../errors'; -import { validateProvisioningProfileAsync } from '../../validators/validateProvisioningProfile'; -import { formatProvisioningProfileFromApple } from '../ProvisioningProfileUtils'; +} from '../../../graphql/generated'; +import { confirmAsync } from '../../../prompts'; +import { Context } from '../../context'; +import { AppLookupParams } from '../api/GraphqlClient'; +import { ProvisioningProfileStoreInfo } from '../appstore/Credentials.types'; +import { MissingCredentialsNonInteractiveError } from '../errors'; +import { validateProvisioningProfileAsync } from '../validators/validateProvisioningProfile'; import { assignBuildCredentialsAsync, getBuildCredentialsAsync, @@ -20,6 +19,7 @@ import { } from './BuildCredentialsUtils'; import { ConfigureProvisioningProfile } from './ConfigureProvisioningProfile'; import { CreateProvisioningProfile } from './CreateProvisioningProfile'; +import { formatProvisioningProfileFromApple } from './ProvisioningProfileUtils'; import { SetupDistributionCertificate } from './SetupDistributionCertificate'; /** diff --git a/packages/eas-cli/src/credentials/ios/actions/UpdateCredentialsJson.ts b/packages/eas-cli/src/credentials/ios/actions/UpdateCredentialsJson.ts index cb52768bee..6440434301 100644 --- a/packages/eas-cli/src/credentials/ios/actions/UpdateCredentialsJson.ts +++ b/packages/eas-cli/src/credentials/ios/actions/UpdateCredentialsJson.ts @@ -1,18 +1,18 @@ -import { IosDistributionType } from '../../../graphql/generated'; +import { IosDistributionType as IosDistributionTypeGraphql } from '../../../graphql/generated'; import Log from '../../../log'; -import { Action, CredentialsManager } from '../../CredentialsManager'; import { Context } from '../../context'; import { updateIosCredentialsAsync } from '../../credentialsJson/update'; -import { AppLookupParams } from '../credentials'; -import { getAppLookupParamsFromContext } from './new/BuildCredentialsUtils'; +import { AppLookupParams } from '../api/GraphqlClient'; -export class UpdateCredentialsJson implements Action { - constructor(private app: AppLookupParams) {} +export class UpdateCredentialsJson { + constructor( + private app: AppLookupParams, + private iosDistributionTypeGraphql: IosDistributionTypeGraphql + ) {} - async runAsync(manager: CredentialsManager, ctx: Context): Promise { + async runAsync(ctx: Context): Promise { Log.log('Updating iOS credentials in credentials.json'); - const appLookupParamsGraphql = getAppLookupParamsFromContext(ctx); - await updateIosCredentialsAsync(ctx, appLookupParamsGraphql, IosDistributionType.AppStore); + await updateIosCredentialsAsync(ctx, this.app, this.iosDistributionTypeGraphql); Log.succeed( 'iOS part of your local credentials.json is synced with values stored on EAS servers.' ); diff --git a/packages/eas-cli/src/credentials/ios/actions/UpdateDistributionCertificate.ts b/packages/eas-cli/src/credentials/ios/actions/UpdateDistributionCertificate.ts deleted file mode 100644 index e6c1e31525..0000000000 --- a/packages/eas-cli/src/credentials/ios/actions/UpdateDistributionCertificate.ts +++ /dev/null @@ -1,87 +0,0 @@ -import chalk from 'chalk'; - -import Log from '../../../log'; -import { confirmAsync } from '../../../prompts'; -import { Action, CredentialsManager } from '../../CredentialsManager'; -import { Context } from '../../context'; -import { getAppLookupParams } from '../credentials'; -import { displayIosUserCredentials } from '../utils/printCredentials'; -import { - provideOrGenerateDistributionCertificateAsync, - selectDistributionCertificateAsync, -} from './DistributionCertificateUtils'; -import { RemoveSpecificProvisioningProfile } from './RemoveProvisioningProfile'; - -export class UpdateDistributionCertificate implements Action { - constructor(private accountName: string) {} - - public async runAsync(manager: CredentialsManager, ctx: Context): Promise { - const selected = await selectDistributionCertificateAsync(ctx, this.accountName); - if (!selected) { - return; - } - const credentials = await ctx.ios.getAllCredentialsAsync(this.accountName); - const apps = credentials.appCredentials.filter(cred => cred.distCredentialsId === selected.id); - const appList = apps.map(appCred => chalk.green(appCred.experienceName)).join(', '); - - if (apps.length > 1) { - if (ctx.nonInteractive) { - throw new Error( - `Start the CLI without the '--non-interactive' flag to update the certificate used by ${appList}.` - ); - } - - const confirm = await confirmAsync({ - message: `You are updating certificate used by ${appList}. Do you want to continue?`, - }); - if (!confirm) { - Log.log('Aborting update process'); - return; - } - } - - await manager.runActionAsync( - new UpdateSpecificDistributionCertificate(selected.id, this.accountName) - ); - - const newDistCert = await ctx.ios.getDistributionCertificateByIdAsync( - selected.id, - this.accountName - ); - displayIosUserCredentials(newDistCert); - Log.newLine(); - } -} - -export class UpdateSpecificDistributionCertificate implements Action { - constructor(private userCredentialsId: number | string, private accountName: string) {} - - async runAsync(manager: CredentialsManager, ctx: Context): Promise { - const credentials = await ctx.ios.getAllCredentialsAsync(this.accountName); - const apps = credentials.appCredentials.filter( - cred => cred.distCredentialsId === this.userCredentialsId - ); - - const newDistCert = await provideOrGenerateDistributionCertificateAsync(ctx, this.accountName); - await ctx.ios.updateDistributionCertificateAsync( - this.userCredentialsId, - this.accountName, - newDistCert - ); - Log.succeed('Updated distribution certificate'); - Log.newLine(); - - for (const appCredentials of apps) { - Log.log( - `Removing provisioning profile for ${appCredentials.experienceName} (${appCredentials.bundleIdentifier})` - ); - const appLookupParams = getAppLookupParams( - appCredentials.experienceName, - appCredentials.bundleIdentifier - ); - await manager.runActionAsync( - new RemoveSpecificProvisioningProfile(appLookupParams, { shouldRevoke: true }) - ); - } - } -} diff --git a/packages/eas-cli/src/credentials/ios/actions/UseDistributionCertificate.ts b/packages/eas-cli/src/credentials/ios/actions/UseDistributionCertificate.ts deleted file mode 100644 index 88bfb93ecf..0000000000 --- a/packages/eas-cli/src/credentials/ios/actions/UseDistributionCertificate.ts +++ /dev/null @@ -1,34 +0,0 @@ -import Log from '../../../log'; -import { Action, CredentialsManager } from '../../CredentialsManager'; -import { Context } from '../../context'; -import { AppLookupParams } from '../credentials'; -import { ConfigureProvisioningProfile } from './ConfigureProvisioningProfile'; -import { selectDistributionCertificateAsync } from './DistributionCertificateUtils'; - -export class UseExistingDistributionCertificate implements Action { - constructor(private app: AppLookupParams) {} - - public async runAsync(manager: CredentialsManager, ctx: Context): Promise { - const selected = await selectDistributionCertificateAsync(ctx, this.app.accountName, { - filterInvalid: true, - }); - if (selected) { - await manager.runActionAsync(new UseSpecificDistributionCertificate(this.app, selected.id)); - } - const profile = await ctx.ios.getProvisioningProfileAsync(this.app); - if (profile) { - await manager.runActionAsync(new ConfigureProvisioningProfile(this.app)); - } - } -} - -export class UseSpecificDistributionCertificate implements Action { - constructor(private app: AppLookupParams, private userCredentialsId: number | string) {} - - public async runAsync(manager: CredentialsManager, ctx: Context): Promise { - await ctx.ios.useDistributionCertificateAsync(this.app, this.userCredentialsId); - Log.succeed( - `Assigned distribution certificate to @${this.app.accountName}/${this.app.projectName} (${this.app.bundleIdentifier})` - ); - } -} diff --git a/packages/eas-cli/src/credentials/ios/actions/new/__mocks__/ConfigureProvisioningProfile.ts b/packages/eas-cli/src/credentials/ios/actions/__mocks__/ConfigureProvisioningProfile.ts similarity index 57% rename from packages/eas-cli/src/credentials/ios/actions/new/__mocks__/ConfigureProvisioningProfile.ts rename to packages/eas-cli/src/credentials/ios/actions/__mocks__/ConfigureProvisioningProfile.ts index 2e1cf95ef3..b9b8751bd9 100644 --- a/packages/eas-cli/src/credentials/ios/actions/new/__mocks__/ConfigureProvisioningProfile.ts +++ b/packages/eas-cli/src/credentials/ios/actions/__mocks__/ConfigureProvisioningProfile.ts @@ -1,11 +1,11 @@ import { AppleDistributionCertificateFragment, AppleProvisioningProfileFragment, -} from '../../../../../graphql/generated'; -import { testProvisioningProfileFragment } from '../../../../__tests__/fixtures-ios'; -import { Context } from '../../../../context'; -import { AppLookupParams } from '../../../api/GraphqlClient'; -import { AppleProvisioningProfileMutationResult } from '../../../api/graphql/mutations/AppleProvisioningProfileMutation'; +} from '../../../../graphql/generated'; +import { testProvisioningProfileFragment } from '../../../__tests__/fixtures-ios'; +import { Context } from '../../../context'; +import { AppLookupParams } from '../../api/GraphqlClient'; +import { AppleProvisioningProfileMutationResult } from '../../api/graphql/mutations/AppleProvisioningProfileMutation'; export class ConfigureProvisioningProfile { constructor( diff --git a/packages/eas-cli/src/credentials/ios/actions/new/__mocks__/CreateProvisioningProfile.ts b/packages/eas-cli/src/credentials/ios/actions/__mocks__/CreateProvisioningProfile.ts similarity index 51% rename from packages/eas-cli/src/credentials/ios/actions/new/__mocks__/CreateProvisioningProfile.ts rename to packages/eas-cli/src/credentials/ios/actions/__mocks__/CreateProvisioningProfile.ts index 17ddbae435..fffa09f65e 100644 --- a/packages/eas-cli/src/credentials/ios/actions/new/__mocks__/CreateProvisioningProfile.ts +++ b/packages/eas-cli/src/credentials/ios/actions/__mocks__/CreateProvisioningProfile.ts @@ -1,8 +1,8 @@ -import { AppleDistributionCertificateFragment } from '../../../../../graphql/generated'; -import { testProvisioningProfileFragment } from '../../../../__tests__/fixtures-ios'; -import { Context } from '../../../../context'; -import { AppLookupParams } from '../../../api/GraphqlClient'; -import { AppleProvisioningProfileMutationResult } from '../../../api/graphql/mutations/AppleProvisioningProfileMutation'; +import { AppleDistributionCertificateFragment } from '../../../../graphql/generated'; +import { testProvisioningProfileFragment } from '../../../__tests__/fixtures-ios'; +import { Context } from '../../../context'; +import { AppLookupParams } from '../../api/GraphqlClient'; +import { AppleProvisioningProfileMutationResult } from '../../api/graphql/mutations/AppleProvisioningProfileMutation'; export class CreateProvisioningProfile { constructor( diff --git a/packages/eas-cli/src/credentials/ios/actions/new/__mocks__/SetupDistributionCertificate.ts b/packages/eas-cli/src/credentials/ios/actions/__mocks__/SetupDistributionCertificate.ts similarity index 59% rename from packages/eas-cli/src/credentials/ios/actions/new/__mocks__/SetupDistributionCertificate.ts rename to packages/eas-cli/src/credentials/ios/actions/__mocks__/SetupDistributionCertificate.ts index e6067502d2..5e8a5da52a 100644 --- a/packages/eas-cli/src/credentials/ios/actions/new/__mocks__/SetupDistributionCertificate.ts +++ b/packages/eas-cli/src/credentials/ios/actions/__mocks__/SetupDistributionCertificate.ts @@ -1,10 +1,10 @@ import { AppleDistributionCertificateFragment, IosDistributionType, -} from '../../../../../graphql/generated'; -import { testDistCertFragmentOneDependency } from '../../../../__tests__/fixtures-ios'; -import { Context } from '../../../../context'; -import { AppLookupParams } from '../../../api/GraphqlClient'; +} from '../../../../graphql/generated'; +import { testDistCertFragmentOneDependency } from '../../../__tests__/fixtures-ios'; +import { Context } from '../../../context'; +import { AppLookupParams } from '../../api/GraphqlClient'; export class SetupDistributionCertificate { constructor(private app: AppLookupParams, private distributionType: IosDistributionType) {} diff --git a/packages/eas-cli/src/credentials/ios/actions/new/__tests__/ConfigureProvisioningProfile-test.ts b/packages/eas-cli/src/credentials/ios/actions/__tests__/ConfigureProvisioningProfile-test.ts similarity index 87% rename from packages/eas-cli/src/credentials/ios/actions/new/__tests__/ConfigureProvisioningProfile-test.ts rename to packages/eas-cli/src/credentials/ios/actions/__tests__/ConfigureProvisioningProfile-test.ts index 4f2bd3b61a..90d11466bd 100644 --- a/packages/eas-cli/src/credentials/ios/actions/new/__tests__/ConfigureProvisioningProfile-test.ts +++ b/packages/eas-cli/src/credentials/ios/actions/__tests__/ConfigureProvisioningProfile-test.ts @@ -1,15 +1,15 @@ -import { confirmAsync } from '../../../../../prompts'; -import { getAppstoreMock, testAuthCtx } from '../../../../__tests__/fixtures-appstore'; -import { createCtxMock } from '../../../../__tests__/fixtures-context'; +import { confirmAsync } from '../../../../prompts'; +import { getAppstoreMock, testAuthCtx } from '../../../__tests__/fixtures-appstore'; +import { createCtxMock } from '../../../__tests__/fixtures-context'; import { testDistCertFragmentNoDependencies, testProvisioningProfile, testProvisioningProfileFragment, -} from '../../../../__tests__/fixtures-ios'; -import { MissingCredentialsNonInteractiveError } from '../../../errors'; +} from '../../../__tests__/fixtures-ios'; +import { MissingCredentialsNonInteractiveError } from '../../errors'; import { getAppLookupParamsFromContext } from '../BuildCredentialsUtils'; import { ConfigureProvisioningProfile } from '../ConfigureProvisioningProfile'; -jest.mock('../../../../../prompts'); +jest.mock('../../../../prompts'); (confirmAsync as jest.Mock).mockImplementation(() => true); describe('ConfigureProvisioningProfile', () => { diff --git a/packages/eas-cli/src/credentials/ios/actions/new/__tests__/CreateProvisioningProfile-test.ts b/packages/eas-cli/src/credentials/ios/actions/__tests__/CreateProvisioningProfile-test.ts similarity index 84% rename from packages/eas-cli/src/credentials/ios/actions/new/__tests__/CreateProvisioningProfile-test.ts rename to packages/eas-cli/src/credentials/ios/actions/__tests__/CreateProvisioningProfile-test.ts index 012b11854a..c411ac0703 100644 --- a/packages/eas-cli/src/credentials/ios/actions/new/__tests__/CreateProvisioningProfile-test.ts +++ b/packages/eas-cli/src/credentials/ios/actions/__tests__/CreateProvisioningProfile-test.ts @@ -1,14 +1,14 @@ -import { confirmAsync } from '../../../../../prompts'; -import { getAppstoreMock, testAuthCtx } from '../../../../__tests__/fixtures-appstore'; -import { createCtxMock } from '../../../../__tests__/fixtures-context'; +import { confirmAsync } from '../../../../prompts'; +import { getAppstoreMock, testAuthCtx } from '../../../__tests__/fixtures-appstore'; +import { createCtxMock } from '../../../__tests__/fixtures-context'; import { testDistCertFragmentNoDependencies, testProvisioningProfile, -} from '../../../../__tests__/fixtures-ios'; -import { MissingCredentialsNonInteractiveError } from '../../../errors'; +} from '../../../__tests__/fixtures-ios'; +import { MissingCredentialsNonInteractiveError } from '../../errors'; import { getAppLookupParamsFromContext } from '../BuildCredentialsUtils'; import { CreateProvisioningProfile } from '../CreateProvisioningProfile'; -jest.mock('../../../../../prompts'); +jest.mock('../../../../prompts'); (confirmAsync as jest.Mock).mockImplementation(() => true); describe('CreateProvisioningProfile', () => { diff --git a/packages/eas-cli/src/credentials/ios/actions/new/__tests__/DistributionCertificateUtils-test.ts b/packages/eas-cli/src/credentials/ios/actions/__tests__/DistributionCertificateUtils-test.ts similarity index 73% rename from packages/eas-cli/src/credentials/ios/actions/new/__tests__/DistributionCertificateUtils-test.ts rename to packages/eas-cli/src/credentials/ios/actions/__tests__/DistributionCertificateUtils-test.ts index 6d8d04baed..fca8683aff 100644 --- a/packages/eas-cli/src/credentials/ios/actions/new/__tests__/DistributionCertificateUtils-test.ts +++ b/packages/eas-cli/src/credentials/ios/actions/__tests__/DistributionCertificateUtils-test.ts @@ -1,12 +1,12 @@ import mockdate from 'mockdate'; -import { AppleDistributionCertificateQuery } from '../../../api/graphql/queries/AppleDistributionCertificateQuery'; +import { AppleDistributionCertificateQuery } from '../../api/graphql/queries/AppleDistributionCertificateQuery'; import { formatDistributionCertificate } from '../DistributionCertificateUtils'; -jest.mock('../../../api/graphql/queries/AppleDistributionCertificateQuery'); +jest.mock('../../api/graphql/queries/AppleDistributionCertificateQuery'); jest.mock('chalk', () => { return { __esModule: true, // this property makes it work - default: { gray: jest.fn(log => log) }, + default: { gray: jest.fn(log => log), underline: jest.fn(log => log) }, }; }); diff --git a/packages/eas-cli/src/credentials/ios/actions/new/__tests__/RemoveDistributionCertificate-test.ts b/packages/eas-cli/src/credentials/ios/actions/__tests__/RemoveDistributionCertificate-test.ts similarity index 94% rename from packages/eas-cli/src/credentials/ios/actions/new/__tests__/RemoveDistributionCertificate-test.ts rename to packages/eas-cli/src/credentials/ios/actions/__tests__/RemoveDistributionCertificate-test.ts index 186f4835bf..1ff1112c71 100644 --- a/packages/eas-cli/src/credentials/ios/actions/new/__tests__/RemoveDistributionCertificate-test.ts +++ b/packages/eas-cli/src/credentials/ios/actions/__tests__/RemoveDistributionCertificate-test.ts @@ -1,13 +1,13 @@ -import { confirmAsync } from '../../../../../prompts'; -import { createCtxMock } from '../../../../__tests__/fixtures-context'; +import { confirmAsync } from '../../../../prompts'; +import { createCtxMock } from '../../../__tests__/fixtures-context'; import { testDistCertFragmentNoDependencies, testDistCertFragmentOneDependency, -} from '../../../../__tests__/fixtures-ios'; +} from '../../../__tests__/fixtures-ios'; import { getAppLookupParamsFromContext } from '../BuildCredentialsUtils'; import { RemoveDistributionCertificate } from '../RemoveDistributionCertificate'; -jest.mock('../../../../../prompts'); +jest.mock('../../../../prompts'); (confirmAsync as jest.Mock).mockImplementation(() => true); describe('RemoveDistributionCertificate', () => { diff --git a/packages/eas-cli/src/credentials/ios/actions/new/__tests__/RemoveProvisioningProfile-test.ts b/packages/eas-cli/src/credentials/ios/actions/__tests__/RemoveProvisioningProfile-test.ts similarity index 91% rename from packages/eas-cli/src/credentials/ios/actions/new/__tests__/RemoveProvisioningProfile-test.ts rename to packages/eas-cli/src/credentials/ios/actions/__tests__/RemoveProvisioningProfile-test.ts index 8d53fd2e66..dec8a87d0d 100644 --- a/packages/eas-cli/src/credentials/ios/actions/new/__tests__/RemoveProvisioningProfile-test.ts +++ b/packages/eas-cli/src/credentials/ios/actions/__tests__/RemoveProvisioningProfile-test.ts @@ -1,4 +1,4 @@ -import { createCtxMock } from '../../../../__tests__/fixtures-context'; +import { createCtxMock } from '../../../__tests__/fixtures-context'; import { getAppLookupParamsFromContext } from '../BuildCredentialsUtils'; import { RemoveProvisioningProfiles } from '../RemoveProvisioningProfile'; diff --git a/packages/eas-cli/src/credentials/ios/actions/new/__tests__/SetupBuildCredentialsFromCredentialsJson-test.ts b/packages/eas-cli/src/credentials/ios/actions/__tests__/SetupBuildCredentialsFromCredentialsJson-test.ts similarity index 94% rename from packages/eas-cli/src/credentials/ios/actions/new/__tests__/SetupBuildCredentialsFromCredentialsJson-test.ts rename to packages/eas-cli/src/credentials/ios/actions/__tests__/SetupBuildCredentialsFromCredentialsJson-test.ts index 0875286370..17870d61d5 100644 --- a/packages/eas-cli/src/credentials/ios/actions/new/__tests__/SetupBuildCredentialsFromCredentialsJson-test.ts +++ b/packages/eas-cli/src/credentials/ios/actions/__tests__/SetupBuildCredentialsFromCredentialsJson-test.ts @@ -1,7 +1,7 @@ -import { asMock } from '../../../../../__tests__/utils'; -import { IosDistributionType } from '../../../../../graphql/generated'; -import { confirmAsync } from '../../../../../prompts'; -import { createCtxMock } from '../../../../__tests__/fixtures-context'; +import { asMock } from '../../../../__tests__/utils'; +import { IosDistributionType } from '../../../../graphql/generated'; +import { confirmAsync } from '../../../../prompts'; +import { createCtxMock } from '../../../__tests__/fixtures-context'; import { testAppleAppIdentifierFragment, testDistCert, @@ -9,13 +9,13 @@ import { testIosAppCredentialsWithBuildCredentialsQueryResult, testProvisioningProfile, testProvisioningProfileFragment, -} from '../../../../__tests__/fixtures-ios'; -import { getNewIosApiMockWithoutCredentials } from '../../../../__tests__/fixtures-new-ios'; -import { readIosCredentialsAsync } from '../../../../credentialsJson/read'; +} from '../../../__tests__/fixtures-ios'; +import { getNewIosApiMockWithoutCredentials } from '../../../__tests__/fixtures-new-ios'; +import { readIosCredentialsAsync } from '../../../credentialsJson/read'; import { getAppLookupParamsFromContext } from '../BuildCredentialsUtils'; import { SetupBuildCredentialsFromCredentialsJson } from '../SetupBuildCredentialsFromCredentialsJson'; -jest.mock('../../../../../prompts'); -jest.mock('../../../../credentialsJson/read'); +jest.mock('../../../../prompts'); +jest.mock('../../../credentialsJson/read'); const originalConsoleLog = console.log; const originalConsoleWarn = console.warn; diff --git a/packages/eas-cli/src/credentials/ios/actions/new/__tests__/SetupInternalProvisioningProfile-test.ts b/packages/eas-cli/src/credentials/ios/actions/__tests__/SetupInternalProvisioningProfile-test.ts similarity index 96% rename from packages/eas-cli/src/credentials/ios/actions/new/__tests__/SetupInternalProvisioningProfile-test.ts rename to packages/eas-cli/src/credentials/ios/actions/__tests__/SetupInternalProvisioningProfile-test.ts index 0529462eac..79276c24e5 100644 --- a/packages/eas-cli/src/credentials/ios/actions/new/__tests__/SetupInternalProvisioningProfile-test.ts +++ b/packages/eas-cli/src/credentials/ios/actions/__tests__/SetupInternalProvisioningProfile-test.ts @@ -1,17 +1,14 @@ -import { asMock } from '../../../../../__tests__/utils'; -import { - IosAppBuildCredentialsFragment, - IosDistributionType, -} from '../../../../../graphql/generated'; -import { promptAsync } from '../../../../../prompts'; -import { getAppstoreMock, testAuthCtx } from '../../../../__tests__/fixtures-appstore'; -import { createCtxMock } from '../../../../__tests__/fixtures-context'; +import { asMock } from '../../../../__tests__/utils'; +import { IosAppBuildCredentialsFragment, IosDistributionType } from '../../../../graphql/generated'; +import { promptAsync } from '../../../../prompts'; +import { getAppstoreMock, testAuthCtx } from '../../../__tests__/fixtures-appstore'; +import { createCtxMock } from '../../../__tests__/fixtures-context'; import { getAllBuildCredentialsAsync } from '../BuildCredentialsUtils'; import { SetupAdhocProvisioningProfile } from '../SetupAdhocProvisioningProfile'; import { SetupInternalProvisioningProfile } from '../SetupInternalProvisioningProfile'; import { SetupProvisioningProfile } from '../SetupProvisioningProfile'; -jest.mock('../../../../../prompts'); +jest.mock('../../../../prompts'); jest.mock('../SetupAdhocProvisioningProfile'); jest.mock('../SetupProvisioningProfile'); jest.mock('../BuildCredentialsUtils', () => ({ getAllBuildCredentialsAsync: jest.fn() })); diff --git a/packages/eas-cli/src/credentials/ios/actions/new/__tests__/SetupProvisioningProfile-test.ts b/packages/eas-cli/src/credentials/ios/actions/__tests__/SetupProvisioningProfile-test.ts similarity index 91% rename from packages/eas-cli/src/credentials/ios/actions/new/__tests__/SetupProvisioningProfile-test.ts rename to packages/eas-cli/src/credentials/ios/actions/__tests__/SetupProvisioningProfile-test.ts index d005fbecb8..d13575bc03 100644 --- a/packages/eas-cli/src/credentials/ios/actions/new/__tests__/SetupProvisioningProfile-test.ts +++ b/packages/eas-cli/src/credentials/ios/actions/__tests__/SetupProvisioningProfile-test.ts @@ -1,25 +1,25 @@ import nullthrows from 'nullthrows'; -import { IosDistributionType } from '../../../../../graphql/generated'; -import { confirmAsync } from '../../../../../prompts'; -import { getAppstoreMock, testAuthCtx } from '../../../../__tests__/fixtures-appstore'; -import { createCtxMock } from '../../../../__tests__/fixtures-context'; +import { IosDistributionType } from '../../../../graphql/generated'; +import { confirmAsync } from '../../../../prompts'; +import { getAppstoreMock, testAuthCtx } from '../../../__tests__/fixtures-appstore'; +import { createCtxMock } from '../../../__tests__/fixtures-context'; import { testAppleAppIdentifierFragment, testIosAppBuildCredentialsFragment, testIosAppCredentialsWithBuildCredentialsQueryResult, -} from '../../../../__tests__/fixtures-ios'; -import { getNewIosApiMockWithoutCredentials } from '../../../../__tests__/fixtures-new-ios'; -import { MissingCredentialsNonInteractiveError } from '../../../errors'; -import { validateProvisioningProfileAsync } from '../../../validators/validateProvisioningProfile'; +} from '../../../__tests__/fixtures-ios'; +import { getNewIosApiMockWithoutCredentials } from '../../../__tests__/fixtures-new-ios'; +import { MissingCredentialsNonInteractiveError } from '../../errors'; +import { validateProvisioningProfileAsync } from '../../validators/validateProvisioningProfile'; import { getAppLookupParamsFromContext } from '../BuildCredentialsUtils'; import { SetupProvisioningProfile } from '../SetupProvisioningProfile'; -jest.mock('../../../../../prompts'); +jest.mock('../../../../prompts'); (confirmAsync as jest.Mock).mockImplementation(() => true); jest.mock('../SetupDistributionCertificate'); jest.mock('../ConfigureProvisioningProfile'); jest.mock('../CreateProvisioningProfile'); -jest.mock('../../../validators/validateProvisioningProfile'); +jest.mock('../../validators/validateProvisioningProfile'); describe('SetupProvisioningProfile', () => { it('repairs existing Provisioning Profile with bad build credentials in Interactive Mode', async () => { diff --git a/packages/eas-cli/src/credentials/ios/actions/new/__tests__/__snapshots__/DistributionCertificateUtils-test.ts.snap b/packages/eas-cli/src/credentials/ios/actions/__tests__/__snapshots__/DistributionCertificateUtils-test.ts.snap similarity index 100% rename from packages/eas-cli/src/credentials/ios/actions/new/__tests__/__snapshots__/DistributionCertificateUtils-test.ts.snap rename to packages/eas-cli/src/credentials/ios/actions/__tests__/__snapshots__/DistributionCertificateUtils-test.ts.snap diff --git a/packages/eas-cli/src/credentials/ios/actions/new/ConfigureProvisioningProfile.ts b/packages/eas-cli/src/credentials/ios/actions/new/ConfigureProvisioningProfile.ts deleted file mode 100644 index cb8cc3230d..0000000000 --- a/packages/eas-cli/src/credentials/ios/actions/new/ConfigureProvisioningProfile.ts +++ /dev/null @@ -1,113 +0,0 @@ -import assert from 'assert'; -import chalk from 'chalk'; -import ora from 'ora'; - -import { - AppleDistributionCertificateFragment, - AppleProvisioningProfileFragment, -} from '../../../../graphql/generated'; -import Log from '../../../../log'; -import { Context } from '../../../context'; -import { AppLookupParams } from '../../api/GraphqlClient'; -import { AppleProvisioningProfileMutationResult } from '../../api/graphql/mutations/AppleProvisioningProfileMutation'; -import { ProvisioningProfileStoreInfo } from '../../appstore/Credentials.types'; -import { AuthCtx } from '../../appstore/authenticate'; -import { MissingCredentialsNonInteractiveError } from '../../errors'; - -export class ConfigureProvisioningProfile { - constructor( - private app: AppLookupParams, - private distributionCertificate: AppleDistributionCertificateFragment, - private originalProvisioningProfile: AppleProvisioningProfileFragment - ) {} - - public async runAsync(ctx: Context): Promise { - if (ctx.nonInteractive) { - throw new MissingCredentialsNonInteractiveError( - 'Configuring Provisioning Profiles is only supported in interactive mode.' - ); - } - const { developerPortalIdentifier, provisioningProfile } = this.originalProvisioningProfile; - if (!developerPortalIdentifier && !provisioningProfile) { - Log.warn("The provisioning profile we have on file cannot be configured on Apple's servers."); - return null; - } - - if (!ctx.appStore.authCtx) { - Log.warn( - "Without access to your Apple account we can't configure provisioning profiles for you." - ); - Log.warn('Make sure to recreate the profile if you selected a new distribution certificate.'); - return null; - } - - const profilesFromApple = await ctx.appStore.listProvisioningProfilesAsync( - this.app.bundleIdentifier - ); - const [matchingProfile] = profilesFromApple.filter(appleInfo => - developerPortalIdentifier - ? appleInfo.provisioningProfileId === developerPortalIdentifier - : appleInfo.provisioningProfile === provisioningProfile - ); - if (!matchingProfile) { - Log.warn( - `Profile ${ - developerPortalIdentifier ? `${developerPortalIdentifier} ` : '' - }not found on Apple Developer Portal.` - ); - return null; - } - - return await this.configureAndUpdateAsync(ctx, ctx.appStore.authCtx, this.app, matchingProfile); - } - - private async configureAndUpdateAsync( - ctx: Context, - authCtx: AuthCtx, - app: AppLookupParams, - profileFromApple: ProvisioningProfileStoreInfo - ): Promise { - const { - developerPortalIdentifier, - certificateP12, - certificatePassword, - serialNumber, - } = this.distributionCertificate; - assert( - certificateP12 && certificatePassword, - 'Distribution Certificate P12 and Password is required' - ); - // configure profile on Apple's Server to use our distCert - const updatedProfile = await ctx.appStore.useExistingProvisioningProfileAsync( - app.bundleIdentifier, - profileFromApple, - { - certId: developerPortalIdentifier ?? undefined, - certP12: certificateP12, - certPassword: certificatePassword, - distCertSerialNumber: serialNumber, - teamId: authCtx.appleId, - } - ); - - const bundleIdTag = `(${app.bundleIdentifier})`; - const slugTag = `@${app.account.name}/${app.projectName}`; - const projectTag = `${chalk.bold(slugTag)} ${chalk.dim(bundleIdTag)}`; - - const spinner = ora(`Updating Expo profile for ${projectTag}`).start(); - try { - const configuredProvisioningProfile = await ctx.newIos.updateProvisioningProfileAsync( - this.originalProvisioningProfile.id, - { - appleProvisioningProfile: updatedProfile.provisioningProfile, - developerPortalIdentifier: updatedProfile.provisioningProfileId, - } - ); - spinner.succeed(`Updated Expo profile for ${projectTag}`); - return configuredProvisioningProfile; - } catch (error) { - spinner.fail(); - throw error; - } - } -} diff --git a/packages/eas-cli/src/credentials/ios/actions/new/CreateDistributionCertificate.ts b/packages/eas-cli/src/credentials/ios/actions/new/CreateDistributionCertificate.ts deleted file mode 100644 index 2d37b4c519..0000000000 --- a/packages/eas-cli/src/credentials/ios/actions/new/CreateDistributionCertificate.ts +++ /dev/null @@ -1,16 +0,0 @@ -import Log from '../../../../log'; -import { Account } from '../../../../user/Account'; -import { Context } from '../../../context'; -import { AppleDistributionCertificateMutationResult } from '../../api/graphql/mutations/AppleDistributionCertificateMutation'; -import { provideOrGenerateDistributionCertificateAsync } from '../DistributionCertificateUtils'; - -export class CreateDistributionCertificate { - constructor(private account: Account) {} - - public async runAsync(ctx: Context): Promise { - const distCert = await provideOrGenerateDistributionCertificateAsync(ctx, this.account.name); - const result = await ctx.newIos.createDistributionCertificateAsync(this.account, distCert); - Log.succeed('Created distribution certificate'); - return result; - } -} diff --git a/packages/eas-cli/src/credentials/ios/actions/new/DistributionCertificateUtils.ts b/packages/eas-cli/src/credentials/ios/actions/new/DistributionCertificateUtils.ts deleted file mode 100644 index 41bcb445bd..0000000000 --- a/packages/eas-cli/src/credentials/ios/actions/new/DistributionCertificateUtils.ts +++ /dev/null @@ -1,142 +0,0 @@ -import assert from 'assert'; -import chalk from 'chalk'; -import dateformat from 'dateformat'; - -import { - AppleDistributionCertificateFragment, - AppleTeamFragment, -} from '../../../../graphql/generated'; -import Log from '../../../../log'; -import { promptAsync } from '../../../../prompts'; -import { Account } from '../../../../user/Account'; -import { fromNow } from '../../../../utils/date'; -import { Context } from '../../../context'; -import { AppLookupParams } from '../../api/GraphqlClient'; -import { filterRevokedDistributionCerts } from '../../appstore/CredentialsUtilsBeta'; - -export function formatDistributionCertificate( - distributionCertificate: AppleDistributionCertificateFragment, - validSerialNumbers?: string[] -): string { - const { - serialNumber, - developerPortalIdentifier, - appleTeam, - validityNotBefore, - validityNotAfter, - updatedAt, - } = distributionCertificate; - let line: string = ''; - if (developerPortalIdentifier) { - line += `Cert ID: ${developerPortalIdentifier}`; - } - line += `${line === '' ? '' : ', '}Serial number: ${serialNumber}${ - appleTeam ? `, ${formatAppleTeam(appleTeam)}` : '' - }`; - line += chalk.gray( - `\n Created: ${fromNow(new Date(validityNotBefore))} ago, Updated: ${fromNow( - new Date(updatedAt) - )} ago,` - ); - line += chalk.gray(`\n Expires: ${dateformat(validityNotAfter, 'expiresHeaderFormat')}`); - const apps = distributionCertificate.iosAppBuildCredentialsList.map( - buildCredentials => buildCredentials.iosAppCredentials.app - ); - if (apps.length) { - const appFullNames = apps.map(app => app.fullName).join(','); - line += chalk.gray(`\n 📲 Used by: ${appFullNames}`); - } - - if (validSerialNumbers?.includes(serialNumber)) { - line += chalk.gray("\n ✅ Currently valid on Apple's servers."); - } else { - line += ''; - } - return line; -} - -function formatAppleTeam({ appleTeamIdentifier, appleTeamName }: AppleTeamFragment): string { - return `Team ID: ${appleTeamIdentifier}${appleTeamName ? `, Team name: ${appleTeamName}` : ''}`; -} - -async function _selectDistributionCertificateAsync( - distCerts: AppleDistributionCertificateFragment[], - validDistributionCertificates?: AppleDistributionCertificateFragment[] -): Promise { - const validDistCertSerialNumbers = validDistributionCertificates?.map( - distCert => distCert.serialNumber - ); - const { chosenDistCert } = await promptAsync({ - type: 'select', - name: 'chosenDistCert', - message: 'Select certificate from the list.', - choices: distCerts.map(distCert => ({ - title: formatDistributionCertificate(distCert, validDistCertSerialNumbers), - value: distCert, - })), - }); - return chosenDistCert; -} - -/** - * select a distribution certificate from an account (validity status shown on a best effort basis) - * */ -export async function selectDistributionCertificateWithDependenciesAsync( - ctx: Context, - account: Account -): Promise { - const distCertsForAccount = await ctx.newIos.getDistributionCertificatesForAccountAsync(account); - if (distCertsForAccount.length === 0) { - Log.warn(`There are no Distribution Certificates available in your EAS account.`); - return null; - } - if (!ctx.appStore.authCtx) { - return _selectDistributionCertificateAsync(distCertsForAccount); - } - - // get valid certs on the developer portal - const certInfoFromApple = await ctx.appStore.listDistributionCertificatesAsync(); - const validDistCerts = await filterRevokedDistributionCerts( - distCertsForAccount, - certInfoFromApple - ); - - return _selectDistributionCertificateAsync(distCertsForAccount, validDistCerts); -} - -/** - * select a distribution certificate from a valid set (curated on a best effort basis) - * */ -export async function selectValidDistributionCertificateAsync( - ctx: Context, - appLookupParams: AppLookupParams -): Promise { - const distCertsForAccount = await ctx.newIos.getDistributionCertificatesForAccountAsync( - appLookupParams.account - ); - if (distCertsForAccount.length === 0) { - Log.warn(`There are no Distribution Certificates available in your EAS account.`); - return null; - } - if (!ctx.appStore.authCtx) { - return _selectDistributionCertificateAsync(distCertsForAccount); - } - - // filter by apple team - assert(ctx.appStore.authCtx, 'authentication to the Apple App Store is required'); - const appleTeamIdentifier = ctx.appStore.authCtx.team.id; - const distCertsForAppleTeam = distCertsForAccount.filter(distCert => { - return !distCert.appleTeam || distCert.appleTeam.appleTeamIdentifier === appleTeamIdentifier; - }); - - // filter by valid certs on the developer portal - const certInfoFromApple = await ctx.appStore.listDistributionCertificatesAsync(); - const validDistCerts = await filterRevokedDistributionCerts( - distCertsForAppleTeam, - certInfoFromApple - ); - Log.log( - `${validDistCerts.length}/${distCertsForAccount.length} Distribution Certificates are currently valid for Apple Team ${ctx.appStore.authCtx?.team.id}.` - ); - return _selectDistributionCertificateAsync(validDistCerts); -} diff --git a/packages/eas-cli/src/credentials/ios/actions/new/RemoveDistributionCertificate.ts b/packages/eas-cli/src/credentials/ios/actions/new/RemoveDistributionCertificate.ts deleted file mode 100644 index 5800afe42c..0000000000 --- a/packages/eas-cli/src/credentials/ios/actions/new/RemoveDistributionCertificate.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { - AppleDistributionCertificateFragment, - AppleProvisioningProfileIdentifiersFragment, -} from '../../../../graphql/generated'; -import Log from '../../../../log'; -import { confirmAsync } from '../../../../prompts'; -import { Account } from '../../../../user/Account'; -import { Context } from '../../../context'; -import { AppLookupParams } from '../../api/GraphqlClient'; -import { selectDistributionCertificateWithDependenciesAsync } from './DistributionCertificateUtils'; -import { RemoveProvisioningProfiles } from './RemoveProvisioningProfile'; - -export class SelectAndRemoveDistributionCertificate { - constructor(private account: Account) {} - - async runAsync(ctx: Context): Promise { - const selected = await selectDistributionCertificateWithDependenciesAsync(ctx, this.account); - if (selected) { - await new RemoveDistributionCertificate(this.account, selected).runAsync(ctx); - Log.succeed('Removed distribution certificate'); - Log.newLine(); - } - } -} - -export class RemoveDistributionCertificate { - constructor( - private account: Account, - private distributionCertificate: AppleDistributionCertificateFragment - ) {} - - public async runAsync(ctx: Context): Promise { - const apps = this.distributionCertificate.iosAppBuildCredentialsList.map( - buildCredentials => buildCredentials.iosAppCredentials.app - ); - if (apps.length !== 0) { - const appFullNames = apps.map(app => app.fullName).join(','); - if (ctx.nonInteractive) { - throw new Error( - `Certificate is currently used by ${appFullNames} and cannot be deleted in non-interactive mode.` - ); - } - const confirm = await confirmAsync({ - message: `You are removing certificate used by ${appFullNames}. Do you want to continue?`, - }); - if (!confirm) { - Log.log('Aborting'); - return; - } - } - - Log.log('Removing Distribution Certificate'); - await ctx.newIos.deleteDistributionCertificateAsync(this.distributionCertificate.id); - - if (this.distributionCertificate.developerPortalIdentifier) { - let shouldRevoke = false; - if (!ctx.nonInteractive) { - shouldRevoke = await confirmAsync({ - message: `Do you also want to revoke this Distribution Certificate on Apple Developer Portal?`, - }); - } else if (ctx.nonInteractive) { - Log.log('Skipping certificate revocation on the Apple Developer Portal.'); - } - if (shouldRevoke) { - await ctx.appStore.revokeDistributionCertificateAsync([ - this.distributionCertificate.developerPortalIdentifier, - ]); - } - } - - await this.removeInvalidProvisioningProfilesAsync(ctx); - } - - private async removeInvalidProvisioningProfilesAsync(ctx: Context): Promise { - const buildCredentialsList = this.distributionCertificate.iosAppBuildCredentialsList; - const appsWithProfilesToRemove: AppLookupParams[] = []; - const profilesToRemove: AppleProvisioningProfileIdentifiersFragment[] = []; - for (const buildCredentials of buildCredentialsList) { - const projectName = buildCredentials.iosAppCredentials.app.slug; - const { bundleIdentifier } = buildCredentials.iosAppCredentials.appleAppIdentifier; - const appLookupParams = { account: this.account, projectName, bundleIdentifier }; - const maybeProvisioningProfile = buildCredentials.provisioningProfile; - if (maybeProvisioningProfile) { - appsWithProfilesToRemove.push(appLookupParams); - profilesToRemove.push(maybeProvisioningProfile); - } - } - await new RemoveProvisioningProfiles(appsWithProfilesToRemove, profilesToRemove).runAsync(ctx); - } -} diff --git a/packages/eas-cli/src/credentials/ios/actions/new/RemoveProvisioningProfile.ts b/packages/eas-cli/src/credentials/ios/actions/new/RemoveProvisioningProfile.ts deleted file mode 100644 index a73e15cefe..0000000000 --- a/packages/eas-cli/src/credentials/ios/actions/new/RemoveProvisioningProfile.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { assert } from '@expo/config'; - -import { AppleProvisioningProfileIdentifiersFragment } from '../../../../graphql/generated'; -import Log from '../../../../log'; -import { Context } from '../../../context'; -import { AppLookupParams } from '../../api/GraphqlClient'; - -export class RemoveProvisioningProfiles { - constructor( - private apps: AppLookupParams[], - private provisioningProfiles: AppleProvisioningProfileIdentifiersFragment[] - ) { - assert( - apps.length === provisioningProfiles.length, - 'apps must correspond to the provisioning profiles being removed' - ); - } - - async runAsync(ctx: Context): Promise { - if (this.provisioningProfiles.length === 0) { - Log.log(`Skipping deletion of Provisioning Profiles`); - return; - } - await ctx.newIos.deleteProvisioningProfilesAsync( - this.provisioningProfiles.map(profile => profile.id) - ); - const appAndBundles = this.apps - .map(app => `@${app.account.name}/${app.projectName} (${app.bundleIdentifier})`) - .join(','); - Log.succeed(`Successfully removed provisioning profiles for ${appAndBundles}`); - } -} diff --git a/packages/eas-cli/src/credentials/ios/actions/new/UpdateCredentialsJson.ts b/packages/eas-cli/src/credentials/ios/actions/new/UpdateCredentialsJson.ts deleted file mode 100644 index 21fd24d013..0000000000 --- a/packages/eas-cli/src/credentials/ios/actions/new/UpdateCredentialsJson.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { IosDistributionType as IosDistributionTypeGraphql } from '../../../../graphql/generated'; -import Log from '../../../../log'; -import { Context } from '../../../context'; -import { updateIosCredentialsAsync } from '../../../credentialsJson/update'; -import { AppLookupParams } from '../../api/GraphqlClient'; - -export class UpdateCredentialsJson { - constructor( - private app: AppLookupParams, - private iosDistributionTypeGraphql: IosDistributionTypeGraphql - ) {} - - async runAsync(ctx: Context): Promise { - Log.log('Updating iOS credentials in credentials.json'); - await updateIosCredentialsAsync(ctx, this.app, this.iosDistributionTypeGraphql); - Log.succeed( - 'iOS part of your local credentials.json is synced with values stored on EAS servers.' - ); - } -} diff --git a/packages/eas-cli/src/credentials/manager/ManageIos.ts b/packages/eas-cli/src/credentials/manager/ManageIos.ts index ee42c6d0ae..0024608378 100644 --- a/packages/eas-cli/src/credentials/manager/ManageIos.ts +++ b/packages/eas-cli/src/credentials/manager/ManageIos.ts @@ -13,15 +13,15 @@ import { ensureActorHasUsername } from '../../user/actions'; import { Action, CredentialsManager } from '../CredentialsManager'; import { Context } from '../context'; import { SetupBuildCredentials } from '../ios/actions/SetupBuildCredentials'; -import { getAppLookupParamsFromContext } from '../ios/actions/new/BuildCredentialsUtils'; -import { CreateDistributionCertificate } from '../ios/actions/new/CreateDistributionCertificate'; -import { selectValidDistributionCertificateAsync } from '../ios/actions/new/DistributionCertificateUtils'; -import { SelectAndRemoveDistributionCertificate } from '../ios/actions/new/RemoveDistributionCertificate'; -import { RemoveProvisioningProfiles } from '../ios/actions/new/RemoveProvisioningProfile'; -import { SetupAdhocProvisioningProfile } from '../ios/actions/new/SetupAdhocProvisioningProfile'; -import { SetupBuildCredentialsFromCredentialsJson } from '../ios/actions/new/SetupBuildCredentialsFromCredentialsJson'; -import { SetupProvisioningProfile } from '../ios/actions/new/SetupProvisioningProfile'; -import { UpdateCredentialsJson } from '../ios/actions/new/UpdateCredentialsJson'; +import { getAppLookupParamsFromContext } from '../ios/actions/BuildCredentialsUtils'; +import { CreateDistributionCertificate } from '../ios/actions/CreateDistributionCertificate'; +import { selectValidDistributionCertificateAsync } from '../ios/actions/DistributionCertificateUtils'; +import { SelectAndRemoveDistributionCertificate } from '../ios/actions/RemoveDistributionCertificate'; +import { RemoveProvisioningProfiles } from '../ios/actions/RemoveProvisioningProfile'; +import { SetupAdhocProvisioningProfile } from '../ios/actions/SetupAdhocProvisioningProfile'; +import { SetupBuildCredentialsFromCredentialsJson } from '../ios/actions/SetupBuildCredentialsFromCredentialsJson'; +import { SetupProvisioningProfile } from '../ios/actions/SetupProvisioningProfile'; +import { UpdateCredentialsJson } from '../ios/actions/UpdateCredentialsJson'; import { AppLookupParams } from '../ios/api/GraphqlClient'; import { displayEmptyIosCredentials,