Skip to content

Commit 521a9f1

Browse files
Saadnajmiclaude
andcommitted
ci: extract Hermes build into separate reusable workflow
Move resolve-hermes, build-hermesc, build-hermes-slice, and assemble-hermes into microsoft-build-hermes.yml. The prebuild workflow now calls it as a single dependency, cleanly separating Hermes compilation from the React Native prebuild pipeline. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent d85874f commit 521a9f1

2 files changed

Lines changed: 219 additions & 212 deletions

File tree

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
name: Build Hermes
2+
3+
on:
4+
workflow_call:
5+
6+
jobs:
7+
resolve-hermes:
8+
name: "Resolve Hermes"
9+
runs-on: macos-15
10+
timeout-minutes: 10
11+
outputs:
12+
hermes-commit: ${{ steps.resolve.outputs.hermes-commit }}
13+
cache-hit: ${{ steps.cache.outputs.cache-hit }}
14+
steps:
15+
- uses: actions/checkout@v4
16+
with:
17+
filter: blob:none
18+
fetch-depth: 0
19+
20+
- name: Setup toolchain
21+
uses: ./.github/actions/microsoft-setup-toolchain
22+
with:
23+
node-version: '22'
24+
platform: macos
25+
26+
- name: Install npm dependencies
27+
run: yarn install
28+
29+
- name: Resolve Hermes commit at merge base
30+
id: resolve
31+
working-directory: packages/react-native
32+
run: |
33+
COMMIT=$(node -e "const {hermesCommitAtMergeBase} = require('./scripts/ios-prebuild/macosVersionResolver'); console.log(hermesCommitAtMergeBase().commit);" 2>&1 | grep -E '^[0-9a-f]{40}$')
34+
echo "hermes-commit=$COMMIT" >> "$GITHUB_OUTPUT"
35+
echo "Resolved Hermes commit: $COMMIT"
36+
37+
- name: Restore Hermes cache
38+
id: cache
39+
uses: actions/cache/restore@v4
40+
with:
41+
key: hermes-v1-${{ steps.resolve.outputs.hermes-commit }}-Debug
42+
path: hermes-destroot
43+
44+
- name: Upload cached Hermes artifacts
45+
if: steps.cache.outputs.cache-hit == 'true'
46+
uses: actions/upload-artifact@v4
47+
with:
48+
name: hermes-artifacts
49+
path: hermes-destroot
50+
retention-days: 30
51+
52+
build-hermesc:
53+
name: "Build hermesc"
54+
if: ${{ needs.resolve-hermes.outputs.cache-hit != 'true' }}
55+
needs: resolve-hermes
56+
runs-on: macos-15
57+
timeout-minutes: 30
58+
steps:
59+
- uses: actions/checkout@v4
60+
with:
61+
filter: blob:none
62+
63+
- name: Setup toolchain
64+
uses: ./.github/actions/microsoft-setup-toolchain
65+
with:
66+
platform: macos
67+
cache-npm-dependencies: ''
68+
69+
- name: Clone Hermes
70+
uses: actions/checkout@v4
71+
with:
72+
repository: facebook/hermes
73+
ref: ${{ needs.resolve-hermes.outputs.hermes-commit }}
74+
path: hermes
75+
76+
- name: Build hermesc
77+
working-directory: hermes
78+
env:
79+
HERMES_PATH: ${{ github.workspace }}/hermes
80+
JSI_PATH: ${{ github.workspace }}/hermes/API/jsi
81+
MAC_DEPLOYMENT_TARGET: '14.0'
82+
run: |
83+
source $GITHUB_WORKSPACE/packages/react-native/sdks/hermes-engine/utils/build-apple-framework.sh
84+
build_host_hermesc
85+
86+
- name: Upload hermesc artifact
87+
uses: actions/upload-artifact@v4
88+
with:
89+
name: hermesc
90+
path: hermes/build_host_hermesc
91+
retention-days: 30
92+
93+
build-hermes-slice:
94+
name: "Hermes ${{ matrix.slice }}"
95+
if: ${{ needs.resolve-hermes.outputs.cache-hit != 'true' }}
96+
needs: [resolve-hermes, build-hermesc]
97+
runs-on: macos-15
98+
timeout-minutes: 45
99+
strategy:
100+
fail-fast: false
101+
matrix:
102+
slice: [iphoneos, iphonesimulator, macosx, xros, xrsimulator]
103+
include:
104+
- slice: iphoneos
105+
platform: ios
106+
- slice: iphonesimulator
107+
platform: ios
108+
- slice: macosx
109+
platform: macos
110+
- slice: xros
111+
platform: visionos
112+
- slice: xrsimulator
113+
platform: visionos
114+
steps:
115+
- uses: actions/checkout@v4
116+
with:
117+
filter: blob:none
118+
119+
- name: Setup toolchain
120+
uses: ./.github/actions/microsoft-setup-toolchain
121+
with:
122+
platform: ${{ matrix.platform }}
123+
cache-npm-dependencies: ''
124+
125+
- name: Clone Hermes
126+
uses: actions/checkout@v4
127+
with:
128+
repository: facebook/hermes
129+
ref: ${{ needs.resolve-hermes.outputs.hermes-commit }}
130+
path: hermes
131+
132+
- name: Download hermesc
133+
uses: actions/download-artifact@v4
134+
with:
135+
name: hermesc
136+
path: hermes/build_host_hermesc
137+
138+
- name: Restore hermesc permissions
139+
run: chmod +x ${{ github.workspace }}/hermes/build_host_hermesc/bin/hermesc
140+
141+
- name: Build Hermes slice (${{ matrix.slice }})
142+
working-directory: hermes
143+
env:
144+
BUILD_TYPE: Debug
145+
HERMES_PATH: ${{ github.workspace }}/hermes
146+
JSI_PATH: ${{ github.workspace }}/hermes/API/jsi
147+
IOS_DEPLOYMENT_TARGET: '15.1'
148+
MAC_DEPLOYMENT_TARGET: '14.0'
149+
XROS_DEPLOYMENT_TARGET: '1.0'
150+
RELEASE_VERSION: '1000.0.0'
151+
run: |
152+
bash $GITHUB_WORKSPACE/packages/react-native/sdks/hermes-engine/utils/build-ios-framework.sh "${{ matrix.slice }}"
153+
154+
- name: Upload slice artifact
155+
uses: actions/upload-artifact@v4
156+
with:
157+
name: hermes-slice-${{ matrix.slice }}
158+
path: hermes/destroot
159+
retention-days: 30
160+
161+
assemble-hermes:
162+
name: "Assemble Hermes xcframework"
163+
if: ${{ needs.resolve-hermes.outputs.cache-hit != 'true' }}
164+
needs: [resolve-hermes, build-hermes-slice]
165+
runs-on: macos-15
166+
timeout-minutes: 15
167+
steps:
168+
- uses: actions/checkout@v4
169+
with:
170+
filter: blob:none
171+
172+
- name: Download all slice artifacts
173+
uses: actions/download-artifact@v4
174+
with:
175+
pattern: hermes-slice-*
176+
path: /tmp/slices
177+
178+
- name: Assemble destroot from slices
179+
run: |
180+
mkdir -p ${{ github.workspace }}/hermes/destroot/Library/Frameworks
181+
for slice_dir in /tmp/slices/hermes-slice-*; do
182+
slice_name=$(basename "$slice_dir" | sed 's/hermes-slice-//')
183+
echo "Copying slice: $slice_name"
184+
cp -R "$slice_dir/Library/Frameworks/$slice_name" ${{ github.workspace }}/hermes/destroot/Library/Frameworks/
185+
# Copy include and bin directories (identical across slices, only need one copy)
186+
if [ -d "$slice_dir/include" ] && [ ! -d ${{ github.workspace }}/hermes/destroot/include ]; then
187+
cp -R "$slice_dir/include" ${{ github.workspace }}/hermes/destroot/
188+
fi
189+
if [ -d "$slice_dir/bin" ]; then
190+
cp -R "$slice_dir/bin" ${{ github.workspace }}/hermes/destroot/
191+
fi
192+
done
193+
echo "Assembled destroot contents:"
194+
ls -la ${{ github.workspace }}/hermes/destroot/Library/Frameworks/
195+
196+
- name: Create universal xcframework
197+
working-directory: hermes
198+
env:
199+
HERMES_PATH: ${{ github.workspace }}/hermes
200+
run: |
201+
source $GITHUB_WORKSPACE/packages/react-native/sdks/hermes-engine/utils/build-apple-framework.sh
202+
create_universal_framework "iphoneos" "iphonesimulator" "macosx" "xros" "xrsimulator"
203+
204+
- name: Save Hermes cache
205+
uses: actions/cache/save@v4
206+
with:
207+
key: hermes-v1-${{ needs.resolve-hermes.outputs.hermes-commit }}-Debug
208+
path: hermes/destroot
209+
210+
- name: Upload Hermes artifacts
211+
uses: actions/upload-artifact@v4
212+
with:
213+
name: hermes-artifacts
214+
path: hermes/destroot
215+
retention-days: 30

0 commit comments

Comments
 (0)