Skip to content

Commit 432bdf0

Browse files
Saadnajmiclaude
andcommitted
refactor: move downloadUpstreamHermesTarball to CI script
downloadUpstreamHermesTarball is only called from CI, not by any library consumer. Move it (and its computeNightlyTarballURL dependency) to .github/scripts/resolve-hermes.mts where it belongs. microsoft-resolveHermes.js is now a pure library with only the functions imported by hermes.js and reactNativeDependencies.js. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent a30b944 commit 432bdf0

2 files changed

Lines changed: 99 additions & 107 deletions

File tree

.github/scripts/resolve-hermes.mts

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,19 @@
99
*
1010
* Each command writes results to $GITHUB_OUTPUT for use in GitHub Actions.
1111
*/
12+
import os from 'node:os';
1213
import { $, echo, fs, path } from 'zx';
1314

1415
// Import library functions from the react-native package
1516
const {
16-
downloadUpstreamHermesTarball,
17+
findMatchingHermesVersion,
18+
findVersionAtMergeBase,
19+
getLatestStableVersionFromNPM,
1720
hermesCommitAtMergeBase,
1821
} = require('../../packages/react-native/scripts/ios-prebuild/microsoft-resolveHermes.js');
22+
const {
23+
computeNightlyTarballURL,
24+
} = require('../../packages/react-native/scripts/ios-prebuild/utils.js');
1925

2026
function setActionOutput(key: string, value: string) {
2127
const outputFile = process.env.GITHUB_OUTPUT;
@@ -24,6 +30,94 @@ function setActionOutput(key: string, value: string) {
2430
}
2531
}
2632

33+
/**
34+
* Downloads the upstream Hermes tarball from Maven or Sonatype.
35+
*
36+
* Tries multiple version resolution strategies in order:
37+
* 1. Mapped version from peerDependencies (stable branches)
38+
* 2. Version at merge base with facebook/react-native (main branch)
39+
* 3. Latest stable version from npm (last resort)
40+
*
41+
* Returns {tarballPath, version} on success, or null if no tarball is available.
42+
*/
43+
async function downloadUpstreamHermesTarball(
44+
buildType: string = 'Debug',
45+
): Promise<{ tarballPath: string; version: string } | null> {
46+
const packageJsonPath = path.resolve(
47+
import.meta.dirname!, '..', '..', 'packages', 'react-native', 'package.json',
48+
);
49+
50+
// Build a list of candidate versions to try (in priority order)
51+
const candidates: string[] = [];
52+
53+
const mapped = findMatchingHermesVersion(packageJsonPath);
54+
if (mapped != null) {
55+
candidates.push(mapped);
56+
}
57+
58+
const mergeBaseVersion = findVersionAtMergeBase();
59+
if (mergeBaseVersion != null && !candidates.includes(mergeBaseVersion)) {
60+
candidates.push(mergeBaseVersion);
61+
}
62+
63+
try {
64+
const latestStable = await getLatestStableVersionFromNPM();
65+
if (!candidates.includes(latestStable)) {
66+
candidates.push(latestStable);
67+
}
68+
} catch {
69+
// npm lookup failed, continue with what we have
70+
}
71+
72+
if (candidates.length === 0) {
73+
echo('Could not determine any upstream version to download Hermes tarball');
74+
return null;
75+
}
76+
77+
const mavenRepoUrl = 'https://repo1.maven.org/maven2';
78+
const namespace = 'com/facebook/react';
79+
80+
for (const version of candidates) {
81+
const releaseUrl = `${mavenRepoUrl}/${namespace}/react-native-artifacts/${version}/react-native-artifacts-${version}-hermes-ios-${buildType.toLowerCase()}.tar.gz`;
82+
const nightlyUrl = await computeNightlyTarballURL(
83+
version,
84+
buildType,
85+
'react-native-artifacts',
86+
`hermes-ios-${buildType.toLowerCase()}.tar.gz`,
87+
);
88+
const urlsToTry = [releaseUrl];
89+
if (nightlyUrl) {
90+
urlsToTry.push(nightlyUrl);
91+
}
92+
93+
for (const tarballUrl of urlsToTry) {
94+
echo(`Trying upstream Hermes tarball (version: ${version}, ${buildType}) at ${tarballUrl}...`);
95+
96+
try {
97+
const response = await fetch(tarballUrl);
98+
if (!response.ok) {
99+
echo(`Tarball not available: ${response.status} ${response.statusText}`);
100+
continue;
101+
}
102+
103+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'hermes-'));
104+
const tarballPath = path.join(tmpDir, 'hermes-ios.tar.gz');
105+
const buffer = await response.arrayBuffer();
106+
fs.writeFileSync(tarballPath, Buffer.from(buffer));
107+
108+
echo(`Downloaded upstream Hermes tarball (${version}) to ${tarballPath}`);
109+
return { tarballPath, version };
110+
} catch (e: any) {
111+
echo(`Error downloading tarball for ${version}: ${e.message}`);
112+
continue;
113+
}
114+
}
115+
}
116+
117+
echo('No upstream Hermes tarball found for any candidate version — will build from source.');
118+
return null;
119+
}
120+
27121
/**
28122
* Extracts an upstream Hermes tarball and recomposes the xcframework to include
29123
* the macOS slice, if needed.

packages/react-native/scripts/ios-prebuild/microsoft-resolveHermes.js

Lines changed: 4 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,15 @@
66
*
77
* [macOS] Resolves Hermes artifacts for macOS fork branches.
88
*
9-
* Library functions for version resolution, downloading upstream Hermes
10-
* tarballs, and resolving Hermes commits. The CI entry point that
11-
* orchestrates these is at .github/scripts/resolve-hermes.mts.
9+
* Library functions for version resolution and resolving Hermes commits.
10+
* The CI entry point that orchestrates downloading, recomposing, and
11+
* caching is at .github/scripts/resolve-hermes.mts.
1212
*
1313
* @flow
1414
* @format
1515
*/
1616

17-
/*:: import type {BuildFlavor} from './types'; */
18-
19-
const {computeNightlyTarballURL, createLogger} = require('./utils');
17+
const {createLogger} = require('./utils');
2018
const {execSync} = require('child_process');
2119
const fs = require('fs');
2220
const os = require('os');
@@ -190,105 +188,6 @@ async function getLatestStableVersionFromNPM() /*: Promise<string> */ {
190188
return json.version;
191189
}
192190

193-
/**
194-
* Downloads the upstream Hermes tarball from Maven or Sonatype.
195-
* The caller is responsible for extracting and recomposing the
196-
* xcframework (e.g. adding the macOS slice to the universal).
197-
*
198-
* Tries multiple version resolution strategies in order:
199-
* 1. Mapped version from peerDependencies (stable branches)
200-
* 2. Version at merge base with facebook/react-native (main branch)
201-
* 3. Latest stable version from npm (last resort)
202-
*
203-
* Returns {tarballPath, version} on success, or null if no tarball is available.
204-
*/
205-
async function downloadUpstreamHermesTarball(
206-
buildType /*: BuildFlavor */ = 'Debug',
207-
) /*: Promise<?{| tarballPath: string, version: string |}> */ {
208-
const packageJsonPath = path.resolve(__dirname, '..', '..', 'package.json');
209-
210-
// Build a list of candidate versions to try (in priority order)
211-
const candidates /*: string[] */ = [];
212-
213-
const mapped = findMatchingHermesVersion(packageJsonPath);
214-
if (mapped != null) {
215-
candidates.push(mapped);
216-
}
217-
218-
const mergeBaseVersion = findVersionAtMergeBase();
219-
if (mergeBaseVersion != null && !candidates.includes(mergeBaseVersion)) {
220-
candidates.push(mergeBaseVersion);
221-
}
222-
223-
try {
224-
const latestStable = await getLatestStableVersionFromNPM();
225-
if (!candidates.includes(latestStable)) {
226-
candidates.push(latestStable);
227-
}
228-
} catch (_) {
229-
// npm lookup failed, continue with what we have
230-
}
231-
232-
if (candidates.length === 0) {
233-
macosLog(
234-
'Could not determine any upstream version to download Hermes tarball',
235-
);
236-
return null;
237-
}
238-
239-
const mavenRepoUrl = 'https://repo1.maven.org/maven2';
240-
const namespace = 'com/facebook/react';
241-
242-
for (const version of candidates) {
243-
// Try both Maven release and nightly (Sonatype snapshot) URLs
244-
const releaseUrl = `${mavenRepoUrl}/${namespace}/react-native-artifacts/${version}/react-native-artifacts-${version}-hermes-ios-${buildType.toLowerCase()}.tar.gz`;
245-
const nightlyUrl = await computeNightlyTarballURL(
246-
version,
247-
buildType,
248-
'react-native-artifacts',
249-
`hermes-ios-${buildType.toLowerCase()}.tar.gz`,
250-
);
251-
const urlsToTry = [releaseUrl];
252-
if (nightlyUrl) {
253-
urlsToTry.push(nightlyUrl);
254-
}
255-
256-
for (const tarballUrl of urlsToTry) {
257-
macosLog(
258-
`Trying upstream Hermes tarball (version: ${version}, ${buildType}) at ${tarballUrl}...`,
259-
);
260-
261-
try {
262-
const response /*: Response */ = await fetch(tarballUrl);
263-
if (!response.ok) {
264-
macosLog(
265-
`Tarball not available: ${response.status} ${response.statusText}`,
266-
);
267-
continue;
268-
}
269-
270-
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'hermes-'));
271-
const tarballPath = path.join(tmpDir, 'hermes-ios.tar.gz');
272-
const buffer = await response.arrayBuffer();
273-
fs.writeFileSync(tarballPath, Buffer.from(buffer));
274-
275-
macosLog(
276-
`Downloaded upstream Hermes tarball (${version}) to ${tarballPath}`,
277-
);
278-
return {tarballPath, version};
279-
} catch (e) {
280-
macosLog(`Error downloading tarball for ${version}: ${e.message}`);
281-
continue;
282-
}
283-
}
284-
}
285-
286-
macosLog(
287-
'No upstream Hermes tarball found for any candidate version — will build from source.',
288-
);
289-
return null;
290-
}
291-
292191
function abort(message /*: string */) {
293192
macosLog(message, 'error');
294193
throw new Error(message);
@@ -299,5 +198,4 @@ module.exports = {
299198
hermesCommitAtMergeBase,
300199
findVersionAtMergeBase,
301200
getLatestStableVersionFromNPM,
302-
downloadUpstreamHermesTarball,
303201
};

0 commit comments

Comments
 (0)