Skip to content

Commit b19f02d

Browse files
amgleitmanAdam Gleitman
andauthored
ci(0.78): Add Hermes to test matrix (#2538)
## Summary: Based on #2524 and #2530. ## Test Plan: CI should pass --------- Co-authored-by: Adam Gleitman <[email protected]>
1 parent 03b0a03 commit b19f02d

File tree

7 files changed

+138
-21
lines changed

7 files changed

+138
-21
lines changed

.ado/jobs/build-test-rntester.yml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,54 @@ parameters:
5050
packager_platform: 'ios'
5151
new_arch_enabled: '1'
5252
use_hermes: '0'
53+
- name: macos_debug_oldarch_hermes
54+
friendly_name: 'macOS, Old Arch, Hermes'
55+
sdk: macosx
56+
configuration: Debug
57+
scheme: RNTester-macOS
58+
packager_platform: 'macos'
59+
new_arch_enabled: '0'
60+
use_hermes: '1'
61+
- name: macos_debug_newarch_hermes
62+
friendly_name: 'macOS, New Arch, Hermes'
63+
sdk: macosx
64+
configuration: Debug
65+
scheme: RNTester-macOS
66+
packager_platform: 'macos'
67+
new_arch_enabled: '1'
68+
use_hermes: '1'
69+
- name: ios_debug_oldarch_hermes
70+
friendly_name: 'iOS, Old Arch, Hermes'
71+
sdk: iphonesimulator
72+
configuration: Debug
73+
scheme: RNTester
74+
packager_platform: 'ios'
75+
new_arch_enabled: '0'
76+
use_hermes: '1'
77+
- name: ios_debug_newarch_hermes
78+
friendly_name: 'iOS, New Arch, Hermes'
79+
sdk: iphonesimulator
80+
configuration: Debug
81+
scheme: RNTester
82+
packager_platform: 'ios'
83+
new_arch_enabled: '1'
84+
use_hermes: '1'
85+
# - name: xros_debug_oldarch_hermes
86+
# friendly_name: 'xrOS, Old Arch, Hermes'
87+
# sdk: xrsimulator
88+
# configuration: Debug
89+
# scheme: RNTester-visionOS
90+
# packager_platform: 'ios'
91+
# new_arch_enabled: '0'
92+
# use_hermes: '1'
93+
# - name: xros_debug_newarch_hermes
94+
# friendly_name: 'xrOS, New Arch, Hermes'
95+
# sdk: xrsimulator
96+
# configuration: Debug
97+
# scheme: RNTester-visionOS
98+
# packager_platform: 'ios'
99+
# new_arch_enabled: '1'
100+
# use_hermes: '1'
53101

54102
jobs:
55103
- ${{ each slice in parameters.appleBuildMatrix }}:

packages/react-native/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@
101101
},
102102
"peerDependencies": {
103103
"@types/react": "^19.0.0",
104-
"react": "^19.0.0"
104+
"react": "^19.0.0",
105+
"react-native": "0.78.2"
105106
},
106107
"peerDependenciesMeta": {
107108
"@types/react": {

packages/react-native/scripts/cocoapods/utils.rb

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -195,16 +195,22 @@ def self.apply_xcode_15_patch(installer, xcodebuild_manager: Xcodebuild)
195195
private
196196

197197
def self.add_build_settings_to_pod(installer, settings_name, settings_value, target_pod_name, configuration_type)
198+
# [macOS
199+
# Since some RN projects might combine multiple platforms into the same Xcode project,
200+
# we'll be much more forgiving with the pod name matching in react-native-macos.
201+
# Could be upstreamed as part of https://github.com/microsoft/react-native-macos/issues/2526.
202+
valid_suffixes = ["", "-iOS", "-macOS", "-visionOS"]
203+
# macOS]
198204
installer.target_installation_results.pod_target_installation_results.each do |pod_name, target_installation_result|
199-
if pod_name.to_s == target_pod_name
205+
if valid_suffixes.any? { |suffix| pod_name.to_s == "#{target_pod_name}#{suffix}" } # [macOS]
200206
target_installation_result.native_target.build_configurations.each do |config|
201-
if configuration_type == nil || (configuration_type != nil && config.type == configuration_type)
202-
config.build_settings[settings_name] ||= '$(inherited) '
203-
config.build_settings[settings_name] << settings_value
204-
end
207+
if configuration_type == nil || (configuration_type != nil && config.type == configuration_type)
208+
config.build_settings[settings_name] ||= '$(inherited) '
209+
config.build_settings[settings_name] << settings_value
205210
end
206211
end
207212
end
213+
end
208214
end
209215

210216
def self.fix_library_search_path(config)

packages/react-native/sdks/hermes-engine/hermes-engine.podspec

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,13 @@ end
2121

2222
# package.json
2323
package = JSON.parse(File.read(File.join(react_native_path, "package.json")))
24-
# [macOS
25-
rn_version = package['version']
26-
version = findLastestVersionWithArtifact(rn_version) || rn_version
27-
# macOS]
24+
version = findMatchingHermesVersion(package) # [macOS] Use special logic instead of just package['version']
2825

2926
source_type = hermes_source_type(version, react_native_path)
3027
source = podspec_source(source_type, version, react_native_path)
3128

29+
version = version || package['version'] # [macOS] If version is nil, fall back to package version so CocoaPods doesn't fail
30+
3231
Pod::Spec.new do |spec|
3332
spec.name = "hermes-engine"
3433
spec.version = version

packages/react-native/sdks/hermes-engine/hermes-utils.rb

Lines changed: 72 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
require 'rexml/document'
88
require 'open3' # [macOS]
99
require 'json' # [macOS]
10+
require 'tmpdir' # [macOS]
1011

1112
HERMES_GITHUB_URL = "https://github.com/facebook/hermes.git"
1213
ENV_BUILD_FROM_SOURCE = "RCT_BUILD_HERMES_FROM_SOURCE"
@@ -177,8 +178,18 @@ def podspec_source_build_from_github_tag(react_native_path)
177178
end
178179

179180
def podspec_source_build_from_github_main()
180-
hermes_log("Using the latest commit from main.")
181-
return {:git => HERMES_GITHUB_URL, :commit => `git ls-remote #{HERMES_GITHUB_URL} main | cut -f 1`.strip}
181+
# hermes_log("Using the latest commit from main.")
182+
# return {:git => HERMES_GITHUB_URL, :commit => `git ls-remote #{HERMES_GITHUB_URL} main | cut -f 1`.strip}
183+
184+
# [macOS
185+
# The logic for this is a bit different on macOS.
186+
# Since react-native-macos lags slightly behind facebook/react-native, we can't always use
187+
# the latest Hermes commit because Hermes and JSI don't always guarantee backwards compatibility.
188+
# Instead, we take the commit hash of Hermes at the time of the merge base with facebook/react-native.
189+
commit = hermes_commit_at_merge_base()
190+
hermes_log("Using Hermes commit from the merge base with facebook/react-native: #{commit}")
191+
return {:git => HERMES_GITHUB_URL, :commit => commit}
192+
# macOS]
182193
end
183194

184195
def podspec_source_download_prebuild_release_tarball(react_native_path, version)
@@ -201,6 +212,51 @@ def artifacts_dir()
201212
return File.join(Pod::Config.instance.project_pods_root, "hermes-engine-artifacts")
202213
end
203214

215+
# [macOS
216+
def hermes_commit_at_merge_base()
217+
# We don't need ls-remote because react-native-macos is a fork of facebook/react-native
218+
fetch_result = `git fetch -q https://github.com/facebook/react-native.git`
219+
if $?.exitstatus != 0
220+
abort <<-EOS
221+
[Hermes] Failed to fetch facebook/react-native into the local repository.
222+
EOS
223+
end
224+
225+
merge_base = `git merge-base FETCH_HEAD HEAD`.strip
226+
if merge_base.empty?
227+
abort <<-EOS
228+
[Hermes] Unable to find the merge base between our HEAD and upstream's HEAD.
229+
EOS
230+
end
231+
232+
timestamp = `git show -s --format=%ci #{merge_base}`.strip
233+
if timestamp.empty?
234+
abort <<-EOS
235+
[Hermes] Unable to extract the timestamp for the merge base (#{merge_base}).
236+
EOS
237+
end
238+
239+
commit = nil
240+
Dir.mktmpdir do |tmpdir|
241+
hermes_git_dir = File.join(tmpdir, "hermes.git")
242+
# Unfortunately we can't use git rev-list on HERMES_GITHUB_URL directly since we're not in that repo.
243+
# Instead, we create a shallow clone to avoid downloading the entire history.
244+
`git clone -q --bare --shallow-since="#{timestamp}" #{HERMES_GITHUB_URL} "#{hermes_git_dir}"`
245+
`git --git-dir="#{hermes_git_dir}" fetch -q --deepen=1`
246+
247+
# If all goes well, this will be the commit hash of Hermes at the time of the merge base
248+
commit = `git --git-dir="#{hermes_git_dir}" rev-list -1 --before="#{timestamp}" HEAD`.strip
249+
if commit.empty?
250+
abort <<-EOS
251+
[Hermes] Unable to find the Hermes commit hash at time #{timestamp}.
252+
EOS
253+
end
254+
end
255+
256+
return commit
257+
end
258+
# macOS]
259+
204260
def hermestag_file(react_native_path)
205261
return File.join(react_native_path, "sdks", ".hermesversion")
206262
end
@@ -240,15 +296,20 @@ def resolve_url_redirects(url)
240296
return (`curl -Ls -o /dev/null -w %{url_effective} \"#{url}\"`)
241297
end
242298

243-
# [macOS react-native-macos does not publish macos specific hermes artifacts
244-
# so we attempt to find the latest patch version of the iOS artifacts and use that
245-
def findLastestVersionWithArtifact(version)
246-
# See https://central.sonatype.org/search/rest-api-guide/ for details on query params
247-
versionWithoutPatch = "#{version.match(/^(\d+\.\d+)/)}"
248-
res, = Open3.capture3("curl -s https://search.maven.org/solrsearch/select?q=g:com.facebook.react+AND+a:react-native-artifacts+AND+v:#{versionWithoutPatch}.*&core=gav&rows=1&wt=json")
249-
wt = JSON.parse(res)
250-
response = wt['response']
251-
return response['docs'][0]['v'] unless response['numFound'] == 0
299+
# [macOS
300+
# Tries to find a suitable Hermes version for a given react-native-macos package.
301+
# For stable branches, we prefer this to be specified as a peer dependency.
302+
def findMatchingHermesVersion(package)
303+
if package['version'] == "1000.0.0"
304+
# The main branch builds from source, so skip this check
305+
return nil
306+
end
307+
308+
if package['peerDependencies']
309+
return package['peerDependencies']['react-native']
310+
end
311+
312+
hermes_log("No matching Hermes version found. Defaulting to main branch, which may be unreliable.")
252313
end
253314
# macOS]
254315

packages/rn-tester/Podfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,5 +107,6 @@ end
107107
# visionOS]
108108

109109
post_install do |installer|
110+
$RN_PLATFORMS = %w[iOS macOS visionOS] # [macOS]
110111
react_native_post_install(installer, @prefix_path, :mac_catalyst_enabled => false)
111112
end

yarn.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10886,6 +10886,7 @@ __metadata:
1088610886
peerDependencies:
1088710887
"@types/react": ^19.0.0
1088810888
react: ^19.0.0
10889+
react-native: 0.78.2
1088910890
peerDependenciesMeta:
1089010891
"@types/react":
1089110892
optional: true

0 commit comments

Comments
 (0)