Skip to content

Commit

Permalink
Revert "Revert "[eas-cli] Use expo-updates runtime version CLI to gen…
Browse files Browse the repository at this point in the history
…erate runtime ve…" (#2264)"

This reverts commit 2b59a5e.
  • Loading branch information
wschurman committed Mar 6, 2024
1 parent 2b59a5e commit 87d3ee8
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 48 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ This is the log of notable changes to EAS CLI and related packages.

- Fix expo-updates package version detection for canaries. ([#2243](https://github.com/expo/eas-cli/pull/2243) by [@wschurman](https://github.com/wschurman))
- Add missing `config` property to `eas.json` schema. ([#2248](https://github.com/expo/eas-cli/pull/2248) by [@sjchmiela](https://github.com/sjchmiela))
- Use expo-updates runtime version CLI to generate runtime versions. ([#2251](https://github.com/expo/eas-cli/pull/2251) by [@wschurman](https://github.com/wschurman))

### 🧹 Chores

Expand Down
6 changes: 2 additions & 4 deletions packages/eas-cli/src/build/metadata.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Updates } from '@expo/config-plugins';
import { Metadata, Platform, sanitizeMetadata } from '@expo/eas-build-job';
import { IosEnterpriseProvisioning } from '@expo/eas-json';
import fs from 'fs-extra';
Expand All @@ -15,6 +14,7 @@ import {
isClassicUpdatesSupportedAsync,
isExpoUpdatesInstalled,
} from '../project/projectUtils';
import { resolveRuntimeVersionAsync } from '../project/resolveRuntimeVersionAsync';
import {
readChannelSafelyAsync as readAndroidChannelSafelyAsync,
readReleaseChannelSafelyAsync as readAndroidReleaseChannelSafelyAsync,
Expand All @@ -37,9 +37,7 @@ export async function collectMetadataAsync<T extends Platform>(
workflow: ctx.workflow,
credentialsSource: ctx.buildProfile.credentialsSource,
sdkVersion: ctx.exp.sdkVersion,
runtimeVersion:
(await Updates.getRuntimeVersionNullableAsync(ctx.projectDir, ctx.exp, ctx.platform)) ??
undefined,
runtimeVersion: (await resolveRuntimeVersionAsync(ctx)) ?? undefined,
reactNativeVersion: await getReactNativeVersionAsync(ctx.projectDir),
...channelOrReleaseChannel,
distribution,
Expand Down
52 changes: 28 additions & 24 deletions packages/eas-cli/src/project/publish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ import {
shouldUseVersionedExpoCLI,
shouldUseVersionedExpoCLIWithExplicitPlatforms,
} from '../utils/expoCli';
import { expoUpdatesCommandAsync } from '../utils/expoUpdatesCli';
import {
ExpoUpdatesCLIInvalidCommandError,
ExpoUpdatesCLIModuleNotFoundError,
expoUpdatesCommandAsync,
} from '../utils/expoUpdatesCli';
import chunk from '../utils/expodash/chunk';
import { truthy } from '../utils/expodash/filter';
import uniqBy from '../utils/expodash/uniqBy';
Expand Down Expand Up @@ -717,31 +721,31 @@ async function getRuntimeVersionForPlatformAsync({
return 'UNVERSIONED';
}

const runtimeVersion = exp[platform]?.runtimeVersion ?? exp.runtimeVersion;
if (typeof runtimeVersion === 'object') {
const policy = runtimeVersion.policy;

if (policy === 'fingerprintExperimental') {
// log to inform the user that the fingerprint has been calculated
Log.warn(
`Calculating native fingerprint for platform ${platform} using current state of the "${platform}" directory. ` +
`If the fingerprint differs from the build's fingerint, ensure the state of your project is consistent ` +
`(repository is clean, ios and android native directories are in the same state as the build if applicable).`
);

const fingerprintRawString = await expoUpdatesCommandAsync(projectDir, [
'fingerprint:generate',
'--platform',
platform,
]);
const fingerprintObject = JSON.parse(fingerprintRawString);
const hash = nullthrows(
fingerprintObject.hash,
'invalid response from expo-update CLI for fingerprint generation'
);
return hash;
try {
const resolvedRuntimeVersionJSONResult = await expoUpdatesCommandAsync(projectDir, [
'runtimeversion:resolve',
'--platform',
platform,
]);
const runtimeVersionResult = JSON.parse(resolvedRuntimeVersionJSONResult);
if (runtimeVersionResult.fingerprintSources) {
Log.debug(`Resolved fingeprint runtime version for platform "${platform}". Sources:`);
Log.debug(runtimeVersionResult.fingerprintSources);
}
return nullthrows(runtimeVersionResult.runtimeVersion);
} catch (e: any) {
// if it's a known set of errors thrown by the CLI it means that we need to default back to the
// previous behavior, otherwise we throw the error since something is wrong
if (
!(e instanceof ExpoUpdatesCLIModuleNotFoundError) &&
!(e instanceof ExpoUpdatesCLIInvalidCommandError)
) {
throw e;
}
}

const runtimeVersion = exp[platform]?.runtimeVersion ?? exp.runtimeVersion;
if (typeof runtimeVersion === 'object') {
const workflow = await resolveWorkflowAsync(
projectDir,
platform as EASBuildJobPlatform,
Expand Down
44 changes: 44 additions & 0 deletions packages/eas-cli/src/project/resolveRuntimeVersionAsync.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { ExpoConfig } from '@expo/config';
import { Updates } from '@expo/config-plugins';

import Log from '../log';
import {
ExpoUpdatesCLIInvalidCommandError,
ExpoUpdatesCLIModuleNotFoundError,
expoUpdatesCommandAsync,
} from '../utils/expoUpdatesCli';

export async function resolveRuntimeVersionAsync({
exp,
platform,
projectDir,
}: {
exp: ExpoConfig;
platform: 'ios' | 'android';
projectDir: string;
}): Promise<string | null> {
try {
const resolvedRuntimeVersionJSONResult = await expoUpdatesCommandAsync(projectDir, [
'runtimeversion:resolve',
'--platform',
platform,
]);
const runtimeVersionResult = JSON.parse(resolvedRuntimeVersionJSONResult);
if (runtimeVersionResult.fingerprintSources) {
Log.debug(`Resolved fingeprint runtime version for platform "${platform}". Sources:`);
Log.debug(runtimeVersionResult.fingerprintSources);
}
return runtimeVersionResult.runtimeVersion ?? null;
} catch (e: any) {
// if expo-updates is not installed, there's no need for a runtime version in the build
if (e instanceof ExpoUpdatesCLIModuleNotFoundError) {
return null;
} else if (e instanceof ExpoUpdatesCLIInvalidCommandError) {
// fall back to the previous behavior (using the @expo/config-plugins eas-cli dependency rather
// than the versioned @expo/config-plugins dependency in the project)
return await Updates.getRuntimeVersionNullableAsync(projectDir, exp, platform);
}

throw e;
}
}
4 changes: 2 additions & 2 deletions packages/eas-cli/src/rollout/actions/CreateRollout.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Updates } from '@expo/config-plugins';
import assert from 'assert';

import { SelectRuntime } from './SelectRuntime';
Expand All @@ -24,6 +23,7 @@ import {
} from '../../graphql/queries/ChannelQuery';
import { UpdateQuery } from '../../graphql/queries/UpdateQuery';
import Log from '../../log';
import { resolveRuntimeVersionAsync } from '../../project/resolveRuntimeVersionAsync';
import { confirmAsync, promptAsync } from '../../prompts';
import { truthy } from '../../utils/expodash/filter';
import {
Expand Down Expand Up @@ -275,7 +275,7 @@ export class CreateRollout implements EASUpdateAction<UpdateChannelBasicInfoFrag
const runtimes = (
await Promise.all(
platforms.map(platform =>
Updates.getRuntimeVersionAsync(ctx.app.projectDir, ctx.app.exp, platform)
resolveRuntimeVersionAsync({ projectDir: ctx.app.projectDir, exp: ctx.app.exp, platform })
)
)
).filter(truthy);
Expand Down
34 changes: 16 additions & 18 deletions packages/eas-cli/src/utils/expoUpdatesCli.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import spawnAsync from '@expo/spawn-async';
import chalk from 'chalk';
import resolveFrom, { silent as silentResolveFrom } from 'resolve-from';

import Log, { link } from '../log';
import { link } from '../log';

export class ExpoUpdatesCLIModuleNotFoundError extends Error {}
export class ExpoUpdatesCLIInvalidCommandError extends Error {}

export async function expoUpdatesCommandAsync(projectDir: string, args: string[]): Promise<string> {
let expoUpdatesCli;
Expand All @@ -12,7 +14,7 @@ export async function expoUpdatesCommandAsync(projectDir: string, args: string[]
resolveFrom(projectDir, 'expo-updates/bin/cli.js');
} catch (e: any) {
if (e.code === 'MODULE_NOT_FOUND') {
throw new Error(
throw new ExpoUpdatesCLIModuleNotFoundError(
`The \`expo-updates\` package was not found. Follow the installation directions at ${link(
'https://docs.expo.dev/bare/installing-expo-modules/'
)}`
Expand All @@ -21,20 +23,16 @@ export async function expoUpdatesCommandAsync(projectDir: string, args: string[]
throw e;
}

const spawnPromise = spawnAsync(expoUpdatesCli, args, {
stdio: ['inherit', 'pipe', 'pipe'], // inherit stdin so user can install a missing expo-cli from inside this command
});
const {
child: { stderr },
} = spawnPromise;
if (!stderr) {
throw new Error('Failed to spawn expo-updates cli');
}
stderr.on('data', data => {
for (const line of data.toString().trim().split('\n')) {
Log.warn(`${chalk.gray('[expo-cli]')} ${line}`);
try {
return (await spawnAsync(expoUpdatesCli, args)).stdout;
} catch (e: any) {
if (e.stderr) {
if ((e.stderr as string).includes('Invalid command')) {
throw new ExpoUpdatesCLIInvalidCommandError(
`The command specified by ${args} was not valid in the \`expo-updates\` CLI.`
);
}
}
});
const result = await spawnPromise;
return result.stdout;
throw e;
}
}

0 comments on commit 87d3ee8

Please sign in to comment.