Skip to content
This repository has been archived by the owner on Jan 18, 2024. It is now read-only.

[cli] refactor IQuit, contextual errors #1891

Merged
merged 3 commits into from
Apr 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 33 additions & 10 deletions packages/expo-cli/src/commands/build/ios/IOSBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import get from 'lodash/get';
import { XDLError } from '@expo/xdl';

import { Dictionary } from 'lodash';
import terminalLink from 'terminal-link';
import BaseBuilder from '../BaseBuilder';
import { PLATFORMS } from '../constants';
import * as utils from '../utils';
Expand All @@ -17,7 +18,7 @@ import { displayProjectCredentials } from '../../../credentials/actions/list';
import { SetupIosDist } from '../../../credentials/views/SetupIosDist';
import { SetupIosPush } from '../../../credentials/views/SetupIosPush';
import { SetupIosProvisioningProfile } from '../../../credentials/views/SetupIosProvisioningProfile';
import CommandError from '../../../CommandError';
import CommandError, { ErrorCodes } from '../../../CommandError';
import log from '../../../log';

import {
Expand Down Expand Up @@ -123,16 +124,38 @@ See https://docs.expo.io/versions/latest/distribution/building-standalone-apps/#
}
await this.produceCredentials(context, experienceName, bundleIdentifier);
} catch (e) {
log(
chalk.bold.red(
'Failed to prepare all credentials. \nThe next time you build, we will automatically use the following configuration:'
)
);
throw e;
} finally {
const credentials = await context.ios.getAllCredentials();
displayProjectCredentials(experienceName, bundleIdentifier, credentials);
if (e.code === ErrorCodes.NON_INTERACTIVE) {
log.newLine();
const link = terminalLink(
'expo.fyi/credentials-non-interactive',
'https://expo.fyi/credentials-non-interactive'
);
log(
chalk.bold.red(
`Additional information needed to setup credentials in non-interactive mode.`
)
);
log(chalk.bold.red(`Learn more about how to resolve this: ${link}.`));
log.newLine();

// We don't want to display project credentials when we bail out due to
// non-interactive mode error, because we are unable to recover without
// user input.
throw new CommandError(
ErrorCodes.NON_INTERACTIVE,
'Unable to proceed, see the above error message.'
);
} else {
log(
chalk.bold.red(
'Failed to prepare all credentials. \nThe next time you build, we will automatically use the following configuration:'
)
);
}
}

const credentials = await context.ios.getAllCredentials();
displayProjectCredentials(experienceName, bundleIdentifier, credentials);
}

async produceCredentials(ctx: Context, experienceName: string, bundleIdentifier: string) {
Expand Down
18 changes: 13 additions & 5 deletions packages/expo-cli/src/credentials/route.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import log from '../log';

import { Context, IView } from './context';
import { IQuit, QuitError, askQuit, doQuit } from './views/Select';
import { AskQuit, DoQuit, IQuit, QuitError } from './views/Select';

export async function runCredentialsManagerStandalone(ctx: Context, startView: IView) {
const manager = new CredentialsManager(ctx, startView, askQuit);
const manager = new CredentialsManager(ctx, startView, new AskQuit());
await manager.run();
}

export async function runCredentialsManager(ctx: Context, startView: IView): Promise<null> {
const manager = new CredentialsManager(ctx, startView, doQuit);
const manager = new CredentialsManager(ctx, startView, new DoQuit());
return await manager.run();
}

Expand Down Expand Up @@ -39,14 +39,22 @@ export class CredentialsManager {
while (true) {
try {
this._currentView =
(await this._currentView.open(this._ctx)) || (await this._quit(this._mainView));
(await this._currentView.open(this._ctx)) || (await this._quit.runAsync(this._mainView));
} catch (error) {
// View quit normally, exit normally
if (error instanceof QuitError) {
return null;
}

// View encountered error
if (this._quit instanceof DoQuit) {
// propagate error up
throw error;
} else {
// fallback to interactive Quit View
log(error);
await new Promise(res => setTimeout(res, 1000));
this._currentView = await this._quit(this._mainView);
this._currentView = await this._quit.runAsync(this._mainView);
}
}
}
Expand Down
42 changes: 24 additions & 18 deletions packages/expo-cli/src/credentials/views/Select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,26 +170,32 @@ export class QuitError extends Error {
}
}

export type IQuit = (view: IView) => Promise<IView>;
export interface IQuit {
runAsync(mainpage: IView): Promise<IView>;
}

export async function doQuit(mainpage: IView): Promise<IView> {
throw new QuitError();
export class DoQuit implements IQuit {
async runAsync(mainpage: IView): Promise<IView> {
throw new QuitError();
}
}

export async function askQuit(mainpage: IView): Promise<IView> {
const { selected } = await prompt([
{
type: 'list',
name: 'selected',
message: 'Do you want to quit Credential Manager',
choices: [
{ value: 'exit', name: 'Quit Credential Manager' },
{ value: 'mainpage', name: 'Go back to experience overview.' },
],
},
]);
if (selected === 'exit') {
process.exit(0);
export class AskQuit implements IQuit {
async runAsync(mainpage: IView): Promise<IView> {
const { selected } = await prompt([
{
type: 'list',
name: 'selected',
message: 'Do you want to quit Credential Manager',
choices: [
{ value: 'exit', name: 'Quit Credential Manager' },
{ value: 'mainpage', name: 'Go back to experience overview.' },
],
},
]);
if (selected === 'exit') {
process.exit(0);
}
return mainpage;
}
return mainpage;
}