Skip to content

Commit e157473

Browse files
authored
[eas-cli] fix expo-updates fingerprinting during update (#2231)
1 parent ba87bb6 commit e157473

File tree

5 files changed

+135
-43
lines changed

5 files changed

+135
-43
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ This is the log of notable changes to EAS CLI and related packages.
88

99
### 🎉 New features
1010

11+
- Fix expo-updates fingerprinting during update. ([#2231](https://github.com/expo/eas-cli/pull/2231) by [@wschurman](https://github.com/wschurman))
12+
1113
### 🐛 Bug fixes
1214

1315
### 🧹 Chores

packages/eas-cli/src/commands/update/index.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -359,12 +359,12 @@ export default class UpdatePublish extends EasCommand {
359359
throw e;
360360
}
361361

362-
const runtimeVersions = await getRuntimeVersionObjectAsync(
362+
const runtimeVersions = await getRuntimeVersionObjectAsync({
363363
exp,
364-
realizedPlatforms,
364+
platforms: realizedPlatforms,
365365
projectDir,
366-
vcsClient
367-
);
366+
vcsClient,
367+
});
368368
const runtimeToPlatformMapping =
369369
getRuntimeToPlatformMappingFromRuntimeVersions(runtimeVersions);
370370

packages/eas-cli/src/commands/update/roll-back-to-embedded.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -201,12 +201,12 @@ export default class UpdateRollBackToEmbedded extends EasCommand {
201201
const gitCommitHash = await vcsClient.getCommitHashAsync();
202202
const isGitWorkingTreeDirty = await vcsClient.hasUncommittedChangesAsync();
203203

204-
const runtimeVersions = await getRuntimeVersionObjectAsync(
204+
const runtimeVersions = await getRuntimeVersionObjectAsync({
205205
exp,
206-
realizedPlatforms,
206+
platforms: realizedPlatforms,
207207
projectDir,
208-
vcsClient
209-
);
208+
vcsClient,
209+
});
210210

211211
let newUpdates: UpdatePublishMutation['updateBranch']['publishUpdateGroups'];
212212
const publishSpinner = ora('Publishing...').start();

packages/eas-cli/src/project/publish.ts

+85-35
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
shouldUseVersionedExpoCLI,
3232
shouldUseVersionedExpoCLIWithExplicitPlatforms,
3333
} from '../utils/expoCli';
34+
import { expoUpdatesCommandAsync } from '../utils/expoUpdatesCli';
3435
import chunk from '../utils/expodash/chunk';
3536
import { truthy } from '../utils/expodash/filter';
3637
import uniqBy from '../utils/expodash/uniqBy';
@@ -675,49 +676,98 @@ export function getRequestedPlatform(
675676
}
676677

677678
/** Get runtime versions grouped by platform. Runtime version is always `null` on web where the platform is always backwards compatible. */
678-
export async function getRuntimeVersionObjectAsync(
679-
exp: ExpoConfig,
680-
platforms: Platform[],
681-
projectDir: string,
682-
vcsClient: Client
683-
): Promise<{ platform: string; runtimeVersion: string }[]> {
684-
for (const platform of platforms) {
685-
if (platform === 'web') {
686-
continue;
687-
}
688-
const isPolicy = typeof (exp[platform]?.runtimeVersion ?? exp.runtimeVersion) === 'object';
689-
if (isPolicy) {
690-
const isManaged =
691-
(await resolveWorkflowAsync(projectDir, platform as EASBuildJobPlatform, vcsClient)) ===
692-
Workflow.MANAGED;
693-
if (!isManaged) {
694-
throw new Error(
695-
`You're currently using the bare workflow, where runtime version policies are not supported. You must set your runtime version manually. For example, define your runtime version as "1.0.0", not {"policy": "appVersion"} in your app config. ${learnMore(
696-
'https://docs.expo.dev/eas-update/runtime-versions'
697-
)}`
698-
);
699-
}
700-
}
701-
}
702-
679+
export async function getRuntimeVersionObjectAsync({
680+
exp,
681+
platforms,
682+
projectDir,
683+
vcsClient,
684+
}: {
685+
exp: ExpoConfig;
686+
platforms: Platform[];
687+
projectDir: string;
688+
vcsClient: Client;
689+
}): Promise<{ platform: string; runtimeVersion: string }[]> {
703690
return await Promise.all(
704-
[...new Set(platforms)].map(async platform => {
705-
if (platform === 'web') {
706-
return { platform: 'web', runtimeVersion: 'UNVERSIONED' };
707-
}
691+
platforms.map(async platform => {
708692
return {
709693
platform,
710-
runtimeVersion: nullthrows(
711-
await Updates.getRuntimeVersionAsync(projectDir, exp, platform),
712-
`Unable to determine runtime version for ${
713-
requestedPlatformDisplayNames[platform]
714-
}. ${learnMore('https://docs.expo.dev/eas-update/runtime-versions/')}`
715-
),
694+
runtimeVersion: await getRuntimeVersionForPlatformAsync({
695+
exp,
696+
platform,
697+
projectDir,
698+
vcsClient,
699+
}),
716700
};
717701
})
718702
);
719703
}
720704

705+
async function getRuntimeVersionForPlatformAsync({
706+
exp,
707+
platform,
708+
projectDir,
709+
vcsClient,
710+
}: {
711+
exp: ExpoConfig;
712+
platform: Platform;
713+
projectDir: string;
714+
vcsClient: Client;
715+
}): Promise<string> {
716+
if (platform === 'web') {
717+
return 'UNVERSIONED';
718+
}
719+
720+
const runtimeVersion = exp[platform]?.runtimeVersion ?? exp.runtimeVersion;
721+
if (typeof runtimeVersion === 'object') {
722+
const policy = runtimeVersion.policy;
723+
724+
if (policy === 'fingerprintExperimental') {
725+
// log to inform the user that the fingerprint has been calculated
726+
Log.warn(
727+
`Calculating native fingerprint for platform ${platform} using current state of the "${platform}" directory. ` +
728+
`If the fingerprint differs from the build's fingerint, ensure the state of your project is consistent ` +
729+
`(repository is clean, ios and android native directories are in the same state as the build if applicable).`
730+
);
731+
732+
const fingerprintRawString = await expoUpdatesCommandAsync(projectDir, [
733+
'fingerprint:generate',
734+
'--platform',
735+
platform,
736+
]);
737+
const fingerprintObject = JSON.parse(fingerprintRawString);
738+
const hash = nullthrows(
739+
fingerprintObject.hash,
740+
'invalid response from expo-update CLI for fingerprint generation'
741+
);
742+
return hash;
743+
}
744+
745+
const workflow = await resolveWorkflowAsync(
746+
projectDir,
747+
platform as EASBuildJobPlatform,
748+
vcsClient
749+
);
750+
if (workflow !== Workflow.MANAGED) {
751+
throw new Error(
752+
`You're currently using the bare workflow, where runtime version policies are not supported. You must set your runtime version manually. For example, define your runtime version as "1.0.0", not {"policy": "appVersion"} in your app config. ${learnMore(
753+
'https://docs.expo.dev/eas-update/runtime-versions'
754+
)}`
755+
);
756+
}
757+
}
758+
759+
const resolvedRuntimeVersion = await Updates.getRuntimeVersionAsync(projectDir, exp, platform);
760+
if (!resolvedRuntimeVersion) {
761+
throw new Error(
762+
`Unable to determine runtime version for ${
763+
requestedPlatformDisplayNames[platform]
764+
}. ${learnMore('https://docs.expo.dev/eas-update/runtime-versions/')}`
765+
);
766+
}
767+
768+
return resolvedRuntimeVersion;
769+
}
770+
721771
export function getRuntimeToPlatformMappingFromRuntimeVersions(
722772
runtimeVersions: { platform: string; runtimeVersion: string }[]
723773
): { runtimeVersion: string; platforms: string[] }[] {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import spawnAsync from '@expo/spawn-async';
2+
import chalk from 'chalk';
3+
import resolveFrom, { silent as silentResolveFrom } from 'resolve-from';
4+
5+
import Log, { link } from '../log';
6+
7+
export async function expoUpdatesCommandAsync(projectDir: string, args: string[]): Promise<string> {
8+
let expoUpdatesCli;
9+
try {
10+
expoUpdatesCli =
11+
silentResolveFrom(projectDir, 'expo-updates/bin/cli') ??
12+
resolveFrom(projectDir, 'expo-updates/bin/cli.js');
13+
} catch (e: any) {
14+
if (e.code === 'MODULE_NOT_FOUND') {
15+
throw new Error(
16+
`The \`expo-updates\` package was not found. Follow the installation directions at ${link(
17+
'https://docs.expo.dev/bare/installing-expo-modules/'
18+
)}`
19+
);
20+
}
21+
throw e;
22+
}
23+
24+
const spawnPromise = spawnAsync(expoUpdatesCli, args, {
25+
stdio: ['inherit', 'pipe', 'pipe'], // inherit stdin so user can install a missing expo-cli from inside this command
26+
});
27+
const {
28+
child: { stderr },
29+
} = spawnPromise;
30+
if (!stderr) {
31+
throw new Error('Failed to spawn expo-updates cli');
32+
}
33+
stderr.on('data', data => {
34+
for (const line of data.toString().trim().split('\n')) {
35+
Log.warn(`${chalk.gray('[expo-cli]')} ${line}`);
36+
}
37+
});
38+
const result = await spawnPromise;
39+
return result.stdout;
40+
}

0 commit comments

Comments
 (0)