diff --git a/packages/expo-cli/src/commands/eas-build/build/__tests__/credentials-test.ts b/packages/expo-cli/src/commands/eas-build/build/__tests__/credentials-test.ts index b1ef84a8e6..4f31e9e1c6 100644 --- a/packages/expo-cli/src/commands/eas-build/build/__tests__/credentials-test.ts +++ b/packages/expo-cli/src/commands/eas-build/build/__tests__/credentials-test.ts @@ -170,7 +170,7 @@ describe('ensureCredentialsAsync', () => { expect(prompts).toHaveBeenCalledTimes(1); }); - it('should should throw an error when local or remote are not present (non interactive)', async () => { + it('should throw an error when local or remote are not present (non interactive)', async () => { const provider = createMockCredentialsProvider({ hasRemote: false, hasLocal: false, diff --git a/packages/expo-cli/src/commands/eas-build/build/action.ts b/packages/expo-cli/src/commands/eas-build/build/action.ts index 9787c8cb80..5d4d02483c 100644 --- a/packages/expo-cli/src/commands/eas-build/build/action.ts +++ b/packages/expo-cli/src/commands/eas-build/build/action.ts @@ -27,7 +27,7 @@ import { printBuildResults, printLogsUrls } from './utils/misc'; interface BuildOptions { platform: BuildCommandPlatform; - skipCredentialsCheck?: boolean; // TODO: noop for now + skipCredentialsCheck?: boolean; skipProjectConfiguration?: boolean; wait?: boolean; profile: string; diff --git a/packages/expo-cli/src/commands/eas-build/build/builders/AndroidBuilder.ts b/packages/expo-cli/src/commands/eas-build/build/builders/AndroidBuilder.ts index 428938804a..a360ab75af 100644 --- a/packages/expo-cli/src/commands/eas-build/build/builders/AndroidBuilder.ts +++ b/packages/expo-cli/src/commands/eas-build/build/builders/AndroidBuilder.ts @@ -49,6 +49,7 @@ class AndroidBuilder implements Builder { const provider = new AndroidCredentialsProvider(this.ctx.projectDir, { projectName: this.ctx.projectName, accountName: this.ctx.accountName, + nonInteractive: this.ctx.nonInteractive, }); await provider.initAsync(); const credentialsSource = await ensureCredentialsAsync( diff --git a/packages/expo-cli/src/commands/eas-build/build/builders/iOSBuilder.ts b/packages/expo-cli/src/commands/eas-build/build/builders/iOSBuilder.ts index 07ff0aa272..f4b34f1bc0 100644 --- a/packages/expo-cli/src/commands/eas-build/build/builders/iOSBuilder.ts +++ b/packages/expo-cli/src/commands/eas-build/build/builders/iOSBuilder.ts @@ -62,6 +62,8 @@ class iOSBuilder implements Builder { projectName: this.ctx.projectName, accountName: this.ctx.accountName, bundleIdentifier, + nonInteractive: this.ctx.nonInteractive, + skipCredentialsCheck: this.ctx.skipCredentialsCheck, }); await provider.initAsync(); const credentialsSource = await ensureCredentialsAsync( diff --git a/packages/expo-cli/src/commands/eas-build/build/credentials.ts b/packages/expo-cli/src/commands/eas-build/build/credentials.ts index 310b608f43..32a0aa479f 100644 --- a/packages/expo-cli/src/commands/eas-build/build/credentials.ts +++ b/packages/expo-cli/src/commands/eas-build/build/credentials.ts @@ -96,9 +96,8 @@ export async function ensureCredentialsAsync( case CredentialsSource.REMOTE: log(log.chalk.bold(USING_REMOTE_CREDENTIALS_MSG)); return CredentialsSource.REMOTE; - case CredentialsSource.AUTO: { + case CredentialsSource.AUTO: log('Resolving credentials source (auto mode)'); return await ensureCredentialsAutoAsync(provider, workflow, nonInteractive); - } } } diff --git a/packages/expo-cli/src/credentials/provider/AndroidCredentialsProvider.ts b/packages/expo-cli/src/credentials/provider/AndroidCredentialsProvider.ts index af6f8b773f..81f2807930 100644 --- a/packages/expo-cli/src/credentials/provider/AndroidCredentialsProvider.ts +++ b/packages/expo-cli/src/credentials/provider/AndroidCredentialsProvider.ts @@ -14,6 +14,7 @@ export interface AndroidCredentials { interface Options { projectName: string; accountName: string; + nonInteractive: boolean; } export default class AndroidCredentialsProvider implements CredentialsProvider { @@ -29,7 +30,7 @@ export default class AndroidCredentialsProvider implements CredentialsProvider { public async initAsync() { await this.ctx.init(this.projectDir, { - nonInteractive: this.ctx.nonInteractive, + nonInteractive: this.options.nonInteractive, }); } diff --git a/packages/expo-cli/src/credentials/provider/__tests__/AndroidCredentialsProvider-test.ts b/packages/expo-cli/src/credentials/provider/__tests__/AndroidCredentialsProvider-test.ts index 764e440719..1bca159c7e 100644 --- a/packages/expo-cli/src/credentials/provider/__tests__/AndroidCredentialsProvider-test.ts +++ b/packages/expo-cli/src/credentials/provider/__tests__/AndroidCredentialsProvider-test.ts @@ -6,6 +6,7 @@ import AndroidCredentialsProvider from '../AndroidCredentialsProvider'; const providerOptions = { projectName: 'slug123', accountName: 'owner123', + nonInteractive: false, }; const mockFetchKeystore = jest.fn(); diff --git a/packages/expo-cli/src/credentials/provider/__tests__/iOSCredentialsProvider-test.ts b/packages/expo-cli/src/credentials/provider/__tests__/iOSCredentialsProvider-test.ts index 8bba7b0d9c..85f23e9567 100644 --- a/packages/expo-cli/src/credentials/provider/__tests__/iOSCredentialsProvider-test.ts +++ b/packages/expo-cli/src/credentials/provider/__tests__/iOSCredentialsProvider-test.ts @@ -1,12 +1,15 @@ import { vol } from 'memfs'; import { CredentialsSource } from '../../../easJson'; +import * as route from '../../route'; import iOSCredentialsProvider from '../iOSCredentialsProvider'; const providerOptions = { projectName: 'slug123', accountName: 'owner123', bundleIdentifier: 'example.bundle.identifier', + nonInteractive: false, + skipCredentialsCheck: false, }; const mockGetDistCert = jest.fn(); @@ -174,7 +177,9 @@ describe('iOSCredentialsProvider', () => { })); const provider = new iOSCredentialsProvider('.', providerOptions); await provider.initAsync(); - await expect(provider.getCredentialsAsync(CredentialsSource.REMOTE)).rejects.toThrowError(); + await expect(provider.getCredentialsAsync(CredentialsSource.REMOTE)).rejects.toThrowError( + 'Provisioning profile is missing' + ); }); it('should return false if dist cert is missging', async () => { mockGetProvisioningProfile.mockImplementation(() => ({ @@ -183,12 +188,32 @@ describe('iOSCredentialsProvider', () => { })); const provider = new iOSCredentialsProvider('.', providerOptions); await provider.initAsync(); - await expect(provider.getCredentialsAsync(CredentialsSource.REMOTE)).rejects.toThrowError(); + await expect(provider.getCredentialsAsync(CredentialsSource.REMOTE)).rejects.toThrowError( + 'Distribution certificate is missing' + ); }); it('should return false if there are no credentials', async () => { const provider = new iOSCredentialsProvider('.', providerOptions); await provider.initAsync(); - await expect(provider.getCredentialsAsync(CredentialsSource.REMOTE)).rejects.toThrowError(); + await expect(provider.getCredentialsAsync(CredentialsSource.REMOTE)).rejects.toThrowError( + 'Distribution certificate is missing' + ); + }); + it('should not run credentials manager if credentials check is skipped', async () => { + const spy = jest.spyOn(route, 'runCredentialsManager').mockImplementation(() => { + throw new Error("Shouldn't be called"); + }); + + const provider = new iOSCredentialsProvider('.', { + ...providerOptions, + skipCredentialsCheck: true, + }); + await provider.initAsync(); + await expect(provider.getCredentialsAsync(CredentialsSource.REMOTE)).rejects.toThrowError( + 'Distribution certificate is missing and credentials check was skipped. Run without --skip-credentials-check to set it up.' + ); + + spy.mockRestore(); }); }); describe('when calling useLocalAsync', () => { diff --git a/packages/expo-cli/src/credentials/provider/iOSCredentialsProvider.ts b/packages/expo-cli/src/credentials/provider/iOSCredentialsProvider.ts index 6cfb48e204..a0b198c886 100644 --- a/packages/expo-cli/src/credentials/provider/iOSCredentialsProvider.ts +++ b/packages/expo-cli/src/credentials/provider/iOSCredentialsProvider.ts @@ -15,16 +15,21 @@ export interface iOSCredentials { }; } +interface Options extends AppLookupParams { + nonInteractive: boolean; + skipCredentialsCheck: boolean; +} + export default class iOSCredentialsProvider implements CredentialsProvider { public readonly platform = 'ios'; private readonly ctx = new Context(); private credentials?: iOSCredentials; - constructor(private projectDir: string, private app: AppLookupParams) {} + constructor(private projectDir: string, private app: Options) {} public async initAsync() { await this.ctx.init(this.projectDir, { - nonInteractive: this.ctx.nonInteractive, + nonInteractive: this.app.nonInteractive, }); } @@ -77,14 +82,29 @@ export default class iOSCredentialsProvider implements CredentialsProvider { return await credentialsJsonReader.readIosCredentialsAsync(this.projectDir); } private async getRemoteAsync(): Promise { - await runCredentialsManager(this.ctx, new SetupIosBuildCredentials(this.app)); + if (!this.app.skipCredentialsCheck) { + log('Skipping credentials check'); + await runCredentialsManager(this.ctx, new SetupIosBuildCredentials(this.app)); + } const distCert = await this.ctx.ios.getDistCert(this.app); if (!distCert) { - throw new Error('Missing distribution certificate'); // shouldn't happen + if (this.app.skipCredentialsCheck) { + throw new Error( + 'Distribution certificate is missing and credentials check was skipped. Run without --skip-credentials-check to set it up.' + ); + } else { + throw new Error('Distribution certificate is missing'); + } } const provisioningProfile = await this.ctx.ios.getProvisioningProfile(this.app); if (!provisioningProfile) { - throw new Error('Missing provisioning profile'); // shouldn't happen + if (this.app.skipCredentialsCheck) { + throw new Error( + 'Provisioning profile is missing and credentials check was skipped. Run without --skip-credentials-check to set it up.' + ); + } else { + throw new Error('Provisioning profile is missing'); + } } return { provisioningProfile: provisioningProfile.provisioningProfile,