Skip to content

Commit 35a1495

Browse files
amgleitmanAdam Gleitman
andauthored
ci(0.76): Add Hermes to test matrix (#2541)
## Summary: Based on #2530. ## Test Plan: CIs should pass. Co-authored-by: Adam Gleitman <[email protected]>
1 parent bdc48b3 commit 35a1495

File tree

7 files changed

+118
-49
lines changed

7 files changed

+118
-49
lines changed

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

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,20 @@ parameters:
1616
packager_platform: 'macos'
1717
new_arch_enabled: '1'
1818
use_hermes: '0'
19-
# - name: macos_oldarch_hermes
20-
# friendly_name: 'macOS, Old Arch, Hermes'
21-
# sdk: macosx
22-
# scheme: RNTester-macOS
23-
# packager_platform: 'macos'
24-
# new_arch_enabled: '1'
25-
# use_hermes: '1'
26-
# - name: macos_newarch_hermes
27-
# friendly_name: 'macOS, New Arch, Hermes'
28-
# sdk: macosx
29-
# scheme: RNTester-macOS
30-
# packager_platform: 'macos'
31-
# new_arch_enabled: '1'
32-
# use_hermes: '1'
19+
- name: macos_oldarch_hermes
20+
friendly_name: 'macOS, Old Arch, Hermes'
21+
sdk: macosx
22+
scheme: RNTester-macOS
23+
packager_platform: 'macos'
24+
new_arch_enabled: '1'
25+
use_hermes: '1'
26+
- name: macos_newarch_hermes
27+
friendly_name: 'macOS, New Arch, Hermes'
28+
sdk: macosx
29+
scheme: RNTester-macOS
30+
packager_platform: 'macos'
31+
new_arch_enabled: '1'
32+
use_hermes: '1'
3333
- name: ios_oldarch_jsc
3434
friendly_name: 'iOS, Old Arch, JSC'
3535
sdk: iphonesimulator
@@ -44,20 +44,20 @@ parameters:
4444
packager_platform: 'ios'
4545
new_arch_enabled: '1'
4646
use_hermes: '0'
47-
# - name: ios_oldarch_hermes
48-
# friendly_name: 'iOS, Old Arch, Hermes'
49-
# sdk: iphonesimulator
50-
# scheme: RNTester
51-
# packager_platform: 'ios'
52-
# new_arch_enabled: '1'
53-
# use_hermes: '1'
54-
# - name: ios_newarch_hermes
55-
# friendly_name: 'iOS, New Arch, Hermes'
56-
# sdk: iphonesimulator
57-
# scheme: RNTester
58-
# packager_platform: 'ios'
59-
# new_arch_enabled: '1'
60-
# use_hermes: '1'
47+
- name: ios_oldarch_hermes
48+
friendly_name: 'iOS, Old Arch, Hermes'
49+
sdk: iphonesimulator
50+
scheme: RNTester
51+
packager_platform: 'ios'
52+
new_arch_enabled: '1'
53+
use_hermes: '1'
54+
- name: ios_newarch_hermes
55+
friendly_name: 'iOS, New Arch, Hermes'
56+
sdk: iphonesimulator
57+
scheme: RNTester
58+
packager_platform: 'ios'
59+
new_arch_enabled: '1'
60+
use_hermes: '1'
6161
- name: xros_oldarch_jsc
6262
friendly_name: 'xrOS, Old Arch, JSC'
6363
sdk: xrsimulator

packages/react-native/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@
102102
},
103103
"peerDependencies": {
104104
"@types/react": "^18.2.6",
105-
"react": "^18.2.0"
105+
"react": "^18.2.0",
106+
"react-native": "0.76.9"
106107
},
107108
"peerDependenciesMeta": {
108109
"@types/react": {

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

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

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

209215
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
@@ -16,14 +16,13 @@ react_native_path = File.dirname(Pod::Executable.execute_command('node', ['-p',
1616

1717
# package.json
1818
package = JSON.parse(File.read(File.join(react_native_path, "package.json")))
19-
# [macOS
20-
rn_version = package['version']
21-
version = findLastestVersionWithArtifact(rn_version) || rn_version
22-
# macOS]
19+
version = findMatchingHermesVersion(package) # [macOS] Use special logic instead of just package['version']
2320

2421
source_type = hermes_source_type(version, react_native_path)
2522
source = podspec_source(source_type, version, react_native_path)
2623

24+
version = version || package['version'] # [macOS] If version is nil, fall back to package version so CocoaPods doesn't fail
25+
2726
Pod::Spec.new do |spec|
2827
spec.name = "hermes-engine"
2928
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"
@@ -175,8 +176,18 @@ def podspec_source_build_from_github_tag(react_native_path)
175176
end
176177

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

182193
def podspec_source_download_prebuild_release_tarball(react_native_path, version)
@@ -199,6 +210,51 @@ def artifacts_dir()
199210
return File.join(Pod::Config.instance.project_pods_root, "hermes-engine-artifacts")
200211
end
201212

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

239-
# [macOS react-native-macos does not publish macos specific hermes artifacts
240-
# so we attempt to find the latest patch version of the iOS artifacts and use that
241-
def findLastestVersionWithArtifact(version)
242-
# See https://central.sonatype.org/search/rest-api-guide/ for details on query params
243-
versionWithoutPatch = "#{version.match(/^(\d+\.\d+)/)}"
244-
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")
245-
wt = JSON.parse(res)
246-
response = wt['response']
247-
return response['docs'][0]['v'] unless response['numFound'] == 0
295+
# [macOS
296+
# Tries to find a suitable Hermes version for a given react-native-macos package.
297+
# For stable branches, we prefer this to be specified as a peer dependency.
298+
def findMatchingHermesVersion(package)
299+
if package['version'] == "1000.0.0"
300+
# The main branch builds from source, so skip this check
301+
return nil
302+
end
303+
304+
if package['peerDependencies']
305+
return package['peerDependencies']['react-native']
306+
end
307+
308+
hermes_log("No matching Hermes version found. Defaulting to main branch, which may be unreliable.")
248309
end
249310
# macOS]
250311

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
@@ -12257,6 +12257,7 @@ __metadata:
1225712257
peerDependencies:
1225812258
"@types/react": ^18.2.6
1225912259
react: ^18.2.0
12260+
react-native: 0.76.9
1226012261
peerDependenciesMeta:
1226112262
"@types/react":
1226212263
optional: true

0 commit comments

Comments
 (0)