Skip to content

Commit

Permalink
[eas-cli] Update: improve DX on first run, correct error message (#1427)
Browse files Browse the repository at this point in the history
  • Loading branch information
Simek authored Oct 27, 2022
1 parent eede0c3 commit fa704c4
Show file tree
Hide file tree
Showing 5 changed files with 202 additions and 61 deletions.
95 changes: 54 additions & 41 deletions packages/eas-cli/src/commands/update/configure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ import chalk from 'chalk';

import { getEASUpdateURL } from '../../api';
import EasCommand from '../../commandUtils/EasCommand';
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
import { AppPlatform } from '../../graphql/generated';
import Log, { learnMore } from '../../log';
import { RequestedPlatform, appPlatformDisplayNames } from '../../platform';
import {
installExpoUpdatesAsync,
isExpoUpdatesInstalledOrAvailable,
} from '../../project/projectUtils';
import { resolveWorkflowAsync } from '../../project/workflow';
import { resolveWorkflowPerPlatformAsync } from '../../project/workflow';
import { syncUpdatesConfigurationAsync as syncAndroidUpdatesConfigurationAsync } from '../../update/android/UpdatesModule';
import { syncUpdatesConfigurationAsync as syncIosUpdatesConfigurationAsync } from '../../update/ios/UpdatesModule';

Expand Down Expand Up @@ -54,38 +55,24 @@ export default class UpdateConfigure extends EasCommand {
await installExpoUpdatesAsync(projectDir);
}

const [androidWorkflow, iosWorkflow] = await Promise.all([
resolveWorkflowAsync(projectDir, Platform.ANDROID),
resolveWorkflowAsync(projectDir, Platform.IOS),
]);
const workflows = await resolveWorkflowPerPlatformAsync(projectDir);

const updatedExp = await configureAppJSONForEASUpdateAsync({
projectDir,
projectId,
exp,
platform,
workflows: {
android: androidWorkflow,
ios: iosWorkflow,
},
projectId,
workflows,
});
Log.withTick(`Configured ${chalk.bold('app.json')} for EAS Update`);

// configure native files for EAS Update
if (
[RequestedPlatform.Android, RequestedPlatform.All].includes(platform) &&
androidWorkflow === Workflow.GENERIC
) {
await syncAndroidUpdatesConfigurationAsync(graphqlClient, projectDir, updatedExp, projectId);
Log.withTick(`Configured ${chalk.bold('AndroidManifest.xml')} for EAS Update`);
}
if (
[RequestedPlatform.Ios, RequestedPlatform.All].includes(platform) &&
iosWorkflow === Workflow.GENERIC
) {
await syncIosUpdatesConfigurationAsync(graphqlClient, projectDir, updatedExp, projectId);
Log.withTick(`Configured ${chalk.bold('Expo.plist')} for EAS Update`);
}
await configureNativeFilesForEASUpdateAsync({
projectDir,
projectId,
exp: updatedExp,
platform,
workflows,
graphqlClient,
});

Log.addNewLineIfNone();
Log.warn(
Expand All @@ -97,31 +84,31 @@ export default class UpdateConfigure extends EasCommand {
}
}

async function configureAppJSONForEASUpdateAsync({
type ConfigureForEASUpdateArgs = {
projectDir: string;
exp: ExpoConfig;
platform: RequestedPlatform;
workflows: Record<Platform, Workflow>;
projectId: string;
};

export async function configureAppJSONForEASUpdateAsync({
projectDir,
exp,
platform,
workflows,
projectId,
}: {
projectDir: string;
exp: ExpoConfig;
platform: RequestedPlatform;
workflows: {
[key in RequestedPlatform.Android | RequestedPlatform.Ios]: Workflow;
};
projectId: string;
}): Promise<ExpoConfig> {
}: ConfigureForEASUpdateArgs): Promise<ExpoConfig> {
// this command is non-interactive in the way it was designed
const easUpdateURL = getEASUpdateURL(projectId);
const updates = { ...exp.updates, url: easUpdateURL };

const androidDefaultRuntimeVersion =
workflows['android'] === Workflow.GENERIC
workflows.android === Workflow.GENERIC
? DEFAULT_BARE_RUNTIME_VERSION
: DEFAULT_MANAGED_RUNTIME_VERSION;
const iosDefaultRuntimeVersion =
workflows['ios'] === Workflow.GENERIC
workflows.ios === Workflow.GENERIC
? DEFAULT_BARE_RUNTIME_VERSION
: DEFAULT_MANAGED_RUNTIME_VERSION;

Expand Down Expand Up @@ -282,9 +269,9 @@ async function configureAppJSONForEASUpdateAsync({
)}`
);
Log.warn(
`In order to finish configuring your project for EAS Update, you are going to need manually add the following to your app.config.js:\n${learnMore(
'https://expo.fyi/eas-update-config.md'
)}\n`
`In order to finish configuring your project for EAS Update, you are going to need manually add the following to your ${chalk.bold(
'app.config.js'
)}:\n${learnMore('https://expo.fyi/eas-update-config.md')}\n`
);
Log.log(chalk.bold(JSON.stringify(newConfigOnlyAddedValues, null, 2)));
Log.addNewLineIfNone();
Expand All @@ -305,9 +292,35 @@ async function configureAppJSONForEASUpdateAsync({
}
assert(result.config, 'A successful result should have a config');

Log.withTick(`Configured ${chalk.bold('app.json')} for EAS Update`);

return result.config.expo;
}

export async function configureNativeFilesForEASUpdateAsync({
projectDir,
exp,
platform,
workflows,
projectId,
graphqlClient,
}: ConfigureForEASUpdateArgs & { graphqlClient: ExpoGraphqlClient }): Promise<void> {
if (
[RequestedPlatform.Android, RequestedPlatform.All].includes(platform) &&
workflows.android === Workflow.GENERIC
) {
await syncAndroidUpdatesConfigurationAsync(graphqlClient, projectDir, exp, projectId);
Log.withTick(`Configured ${chalk.bold('AndroidManifest.xml')} for EAS Update`);
}
if (
[RequestedPlatform.Ios, RequestedPlatform.All].includes(platform) &&
workflows.ios === Workflow.GENERIC
) {
await syncIosUpdatesConfigurationAsync(graphqlClient, projectDir, exp, projectId);
Log.withTick(`Configured ${chalk.bold('Expo.plist')} for EAS Update`);
}
}

function isRuntimeEqual(
runtimeVersionA: string | { policy: 'sdkVersion' | 'nativeVersion' | 'appVersion' },
runtimeVersionB: string | { policy: 'sdkVersion' | 'nativeVersion' | 'appVersion' }
Expand Down
127 changes: 110 additions & 17 deletions packages/eas-cli/src/commands/update/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { selectBranchOnAppAsync } from '../../branch/queries';
import { BranchNotFoundError, getDefaultBranchNameAsync } from '../../branch/utils';
import { getUpdateGroupUrl } from '../../build/utils/url';
import EasCommand from '../../commandUtils/EasCommand';
import { DynamicConfigContextFn } from '../../commandUtils/context/DynamicProjectConfigContextField';
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
import { EasNonInteractiveAndJsonFlags } from '../../commandUtils/flags';
import { getPaginatedQueryOptions } from '../../commandUtils/pagination';
Expand All @@ -28,6 +29,7 @@ import { BranchQuery } from '../../graphql/queries/BranchQuery';
import { UpdateQuery } from '../../graphql/queries/UpdateQuery';
import Log, { learnMore, link } from '../../log';
import { ora } from '../../ora';
import { RequestedPlatform, requestedPlatformDisplayNames } from '../../platform';
import {
getOwnerAccountForProjectIdAsync,
installExpoUpdatesAsync,
Expand All @@ -41,8 +43,8 @@ import {
isUploadedAssetCountAboveWarningThreshold,
uploadAssetsAsync,
} from '../../project/publish';
import { resolveWorkflowAsync } from '../../project/workflow';
import { confirmAsync, promptAsync } from '../../prompts';
import { resolveWorkflowAsync, resolveWorkflowPerPlatformAsync } from '../../project/workflow';
import { confirmAsync, promptAsync, selectAsync } from '../../prompts';
import { selectUpdateGroupOnBranchAsync } from '../../update/queries';
import { formatUpdateMessage } from '../../update/utils';
import {
Expand All @@ -57,6 +59,10 @@ import { maybeWarnAboutEasOutagesAsync } from '../../utils/statuspageService';
import { getVcsClient } from '../../vcs';
import { createUpdateBranchOnAppAsync } from '../branch/create';
import { createUpdateChannelOnAppAsync } from '../channel/create';
import {
configureAppJSONForEASUpdateAsync,
configureNativeFilesForEASUpdateAsync,
} from './configure';

export const defaultPublishPlatforms: PublishPlatform[] = ['android', 'ios'];
export type PublishPlatformFlag = PublishPlatform | 'all';
Expand Down Expand Up @@ -209,7 +215,11 @@ export default class UpdatePublish extends EasCommand {
// If a group was specified, that means we are republishing it.
republish = republish || !!group;

const { exp, projectId, projectDir } = await getDynamicProjectConfigAsync({
const {
exp: expBeforeRuntimeVersionUpdate,
projectId,
projectDir,
} = await getDynamicProjectConfigAsync({
isPublicConfig: true,
});

Expand All @@ -221,7 +231,10 @@ export default class UpdatePublish extends EasCommand {

const codeSigningInfo = await getCodeSigningInfoAsync(expPrivate, privateKeyPath);

const hasExpoUpdates = isExpoUpdatesInstalledOrAvailable(projectDir, exp.sdkVersion);
const hasExpoUpdates = isExpoUpdatesInstalledOrAvailable(
projectDir,
expBeforeRuntimeVersionUpdate.sdkVersion
);
if (!hasExpoUpdates && nonInteractive) {
Errors.error(
`${chalk.bold(
Expand All @@ -245,7 +258,16 @@ export default class UpdatePublish extends EasCommand {
}
}

const runtimeVersions = await getRuntimeVersionObjectAsync(exp, platformFlag, projectDir);
const [runtimeVersions, exp] = await getRuntimeVersionObjectAsync(
expBeforeRuntimeVersionUpdate,
platformFlag,
projectDir,
projectId,
nonInteractive,
graphqlClient,
getDynamicProjectConfigAsync
);

await checkEASUpdateURLIsSetAsync(exp, projectId);

if (!branchName) {
Expand Down Expand Up @@ -327,7 +349,7 @@ export default class UpdatePublish extends EasCommand {
if (updatesToRepublishFilteredByPlatform.length !== defaultPublishPlatforms.length) {
Log.warn(`You are republishing an update that wasn't published for all platforms.`);
}
publicationPlatformMessage = `The republished update will appear on the same plaforms it was originally published on: ${updatesToRepublishFilteredByPlatform
publicationPlatformMessage = `The republished update will appear on the same platforms it was originally published on: ${updatesToRepublishFilteredByPlatform
.map(update => update.platform)
.join(', ')}`;
} else {
Expand Down Expand Up @@ -579,11 +601,29 @@ export default class UpdatePublish extends EasCommand {
}
}

function transformRuntimeVersions(exp: ExpoConfig, platforms: Platform[]): Record<string, string> {
return Object.fromEntries(
platforms.map(platform => [
platform,
nullthrows(
Updates.getRuntimeVersion(exp, platform),
`Unable to determine runtime version for ${
requestedPlatformDisplayNames[platform]
}. ${learnMore('https://docs.expo.dev/eas-update/runtime-versions/')}`
),
])
);
}

async function getRuntimeVersionObjectAsync(
exp: ExpoConfig,
platformFlag: PublishPlatformFlag,
projectDir: string
): Promise<Record<string, string>> {
projectDir: string,
projectId: string,
nonInteractive: boolean,
graphqlClient: ExpoGraphqlClient,
getDynamicProjectConfigAsync: DynamicConfigContextFn
): Promise<[Record<string, string>, ExpoConfig]> {
const platforms = (platformFlag === 'all' ? ['android', 'ios'] : [platformFlag]) as Platform[];

for (const platform of platforms) {
Expand All @@ -598,15 +638,68 @@ async function getRuntimeVersionObjectAsync(
}
}

return Object.fromEntries(
platforms.map(platform => [
platform,
nullthrows(
Updates.getRuntimeVersion(exp, platform),
`Unable to determine runtime version for ${platform}`
),
])
);
try {
return [transformRuntimeVersions(exp, platforms), exp];
} catch (error: any) {
if (nonInteractive) {
throw error;
}

Log.fail(error.message);

const runConfig = await selectAsync(
`Configure runtime version in ${chalk.bold('app.json')} automatically for EAS Update?`,
[
{ title: 'Yes', value: true },
{
title: 'No, I will set the runtime version manually (EAS CLI exits)',
value: false,
},
]
);

if (!runConfig) {
Errors.exit(1);
}

const workflows = await resolveWorkflowPerPlatformAsync(projectDir);
await configureAppJSONForEASUpdateAsync({
exp,
projectDir,
projectId,
platform: platformFlag as RequestedPlatform,
workflows,
});

const newConfig: ExpoConfig = (await getDynamicProjectConfigAsync({ isPublicConfig: true }))
.exp;

await configureNativeFilesForEASUpdateAsync({
exp: newConfig,
projectDir,
projectId,
platform: platformFlag as RequestedPlatform,
workflows,
graphqlClient,
});

const continueWithChanges = await selectAsync(
`Continue update process with uncommitted changes in repository?`,
[
{ title: 'Yes', value: true },
{
title: 'No, I will commit the modified files first (EAS CLI exits)',
value: false,
},
]
);

if (!continueWithChanges) {
Errors.exit(1);
}

return [transformRuntimeVersions(newConfig, platforms), newConfig];
}
}

async function checkEASUpdateURLIsSetAsync(exp: ExpoConfig, projectId: string): Promise<void> {
Expand Down
4 changes: 4 additions & 0 deletions packages/eas-cli/src/log.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ export default class Log {
Log.warn(`› ${chalk.bold('--' + flag)} flag is deprecated. ${message}`);
}

public static fail(message: string): void {
Log.log(`${chalk.red(logSymbols.error)} ${message}`);
}

public static succeed(message: string): void {
Log.log(`${chalk.green(logSymbols.success)} ${message}`);
}
Expand Down
Loading

0 comments on commit fa704c4

Please sign in to comment.