build-hermes-macos workflow (facebook/hermes)
The build-hermes-macos workflow from facebook/hermes, explained and optimized by Latchkey.
CI health: A - excellent
Run this on Latchkey for self-healing, caching, and up to 58% lower cost.
Grade your own workflow free or run it on Latchkey →What it does
This is the build-hermes-macos workflow from the facebook/hermes repository, a real project running GitHub Actions. It is shown here with attribution under its MIT license.
Below, Latchkey shows a faster, safer version produced by its optimization engine.
The workflow
name: build-hermes-macos
on: workflow_call
jobs:
build-hermes-macos:
runs-on: macos-15
continue-on-error: true
env:
HERMES_TARBALL_ARTIFACTS_DIR: /tmp/hermes/hermes-runtime-darwin
strategy:
fail-fast: false
matrix:
flavor: [Debug, Release]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup xcode
uses: ./.github/actions/setup-xcode
- name: Setup node.js
uses: ./.github/actions/setup-node
- name: Yarn Install Dependencies
uses: ./.github/actions/yarn-install
- name: Download slice artifacts
uses: actions/download-artifact@v4
with:
pattern: slice-*-${{ matrix.flavor }}
path: .
merge-multiple: true
- name: Unzip slices
shell: bash
run: |
ls -l .
tar -xzv -f build_catalyst_${{ matrix.flavor }}.tar.gz
tar -xzv -f build_iphoneos_${{ matrix.flavor }}.tar.gz
tar -xzv -f build_iphonesimulator_${{ matrix.flavor }}.tar.gz
tar -xzv -f build_appletvos_${{ matrix.flavor }}.tar.gz
tar -xzv -f build_appletvsimulator_${{ matrix.flavor }}.tar.gz
tar -xzv -f build_macosx_${{ matrix.flavor }}.tar.gz
tar -xzv -f build_xros_${{ matrix.flavor }}.tar.gz
tar -xzv -f build_xrsimulator_${{ matrix.flavor }}.tar.gz
- name: Move back build folders
shell: bash
run: |
ls -l build_*
mv build_catalyst_${{ matrix.flavor }} build_catalyst
mv build_iphoneos_${{ matrix.flavor }} build_iphoneos
mv build_iphonesimulator_${{ matrix.flavor }} build_iphonesimulator
mv build_appletvos_${{ matrix.flavor }} build_appletvos
mv build_appletvsimulator_${{ matrix.flavor }} build_appletvsimulator
mv build_macosx_${{ matrix.flavor }} build_macosx
mv build_xros_${{ matrix.flavor }} build_xros
mv build_xrsimulator_${{ matrix.flavor }} build_xrsimulator
- name: Prepare destroot folder
shell: bash
run: ./utils/build-apple-framework.sh prepare_dest_root
- name: Create universal xcframework
shell: bash
run: |
echo "[HERMES] Creating the universal framework"
./utils/build-apple-framework.sh build_framework
chmod +x ./destroot/bin/hermesc
- name: Package the Hermes Apple frameworks
shell: bash
run: |
BUILD_TYPE="${{ matrix.flavor }}"
echo "Packaging Hermes Apple frameworks for $BUILD_TYPE build type"
TARBALL_OUTPUT_DIR=$(mktemp -d /tmp/hermes-tarball-output-XXXXXXXX)
echo "Packaging Hermes Apple frameworks for $BUILD_TYPE build type"
TARBALL_OUTPUT_PATH=$(node ./utils/scripts/hermes/create-tarball.js \
--inputDir . \
--buildType "$BUILD_TYPE" \
--outputDir $TARBALL_OUTPUT_DIR)
echo "Hermes tarball saved to $TARBALL_OUTPUT_PATH"
mkdir -p $HERMES_TARBALL_ARTIFACTS_DIR
cp $TARBALL_OUTPUT_PATH $HERMES_TARBALL_ARTIFACTS_DIR/.
mkdir -p /tmp/hermes/osx-bin/${{ matrix.flavor }}
cp ./build_macosx/bin/* /tmp/hermes/osx-bin/${{ matrix.flavor }}
ls -lR /tmp/hermes/osx-bin/
- name: Create dSYM archive
shell: bash
run: |
FLAVOR=${{ matrix.flavor }}
WORKING_DIR="/tmp/hermes_tmp/dSYM/$FLAVOR"
mkdir -p "$WORKING_DIR/macosx"
mkdir -p "$WORKING_DIR/catalyst"
mkdir -p "$WORKING_DIR/iphoneos"
mkdir -p "$WORKING_DIR/iphonesimulator"
mkdir -p "$WORKING_DIR/appletvos"
mkdir -p "$WORKING_DIR/appletvsimulator"
mkdir -p "$WORKING_DIR/xros"
mkdir -p "$WORKING_DIR/xrsimulator"
DSYM_FILE_PATH=lib/hermesvm.framework.dSYM
cp -r build_macosx/$DSYM_FILE_PATH "$WORKING_DIR/macosx/"
cp -r build_catalyst/$DSYM_FILE_PATH "$WORKING_DIR/catalyst/"
cp -r build_iphoneos/$DSYM_FILE_PATH "$WORKING_DIR/iphoneos/"
cp -r build_iphonesimulator/$DSYM_FILE_PATH "$WORKING_DIR/iphonesimulator/"
cp -r build_appletvos/$DSYM_FILE_PATH "$WORKING_DIR/appletvos/"
cp -r build_appletvsimulator/$DSYM_FILE_PATH "$WORKING_DIR/appletvsimulator/"
cp -r build_xros/$DSYM_FILE_PATH "$WORKING_DIR/xros/"
cp -r build_xrsimulator/$DSYM_FILE_PATH "$WORKING_DIR/xrsimulator/"
DEST_DIR="/tmp/hermes/dSYM/$FLAVOR"
tar -C "$WORKING_DIR" -czvf "hermesvm.framework.dSYM" .
mkdir -p "$DEST_DIR"
mv "hermesvm.framework.dSYM" "$DEST_DIR"
- name: Upload hermes dSYM artifacts
uses: actions/upload-artifact@v4.3.4
with:
name: hermes-dSYM-${{ matrix.flavor }}
path: /tmp/hermes/dSYM/${{ matrix.flavor }}
- name: Upload hermes Runtime artifacts
uses: actions/upload-artifact@v4.3.4
with:
name: hermes-darwin-bin-${{ matrix.flavor }}
path: /tmp/hermes/hermes-runtime-darwin/hermes-ios-${{ matrix.flavor }}.tar.gz
- name: Upload hermes osx artifacts
uses: actions/upload-artifact@v4.3.4
with:
name: hermes-osx-bin-${{ matrix.flavor }}
path: /tmp/hermes/osx-bin/${{ matrix.flavor }}
- name: Upload Hermes Artifacts
uses: actions/cache/save@v4
if: ${{ github.ref == 'refs/heads/main' || contains(github.ref, '-stable') }} # To avoid that the cache explode.
with:
key: v4-hermes-artifacts-${{ matrix.flavor }}-${{ matrix.hermes-version }}-${{ matrix.react-native-version }}-${{ hashFiles('./packages/react-native/sdks/hermes-engine/utils/build-apple-framework.sh') }}
path: |
/tmp/hermes/osx-bin/${{ matrix.flavor }}
/tmp/hermes/dSYM/${{ matrix.flavor }}
/tmp/hermes/hermes-runtime-darwin/hermes-ios-${{ matrix.flavor }}.tar.gz
The same workflow, on Latchkey
Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.
name: build-hermes-macos on: workflow_call jobs: build-hermes-macos: timeout-minutes: 30 runs-on: macos-15 continue-on-error: true env: HERMES_TARBALL_ARTIFACTS_DIR: /tmp/hermes/hermes-runtime-darwin strategy: fail-fast: false matrix: flavor: [Debug, Release] steps: - name: Checkout uses: actions/checkout@v4 - name: Setup xcode uses: ./.github/actions/setup-xcode - name: Setup node.js uses: ./.github/actions/setup-node - name: Yarn Install Dependencies uses: ./.github/actions/yarn-install - name: Download slice artifacts uses: actions/download-artifact@v4 with: pattern: slice-*-${{ matrix.flavor }} path: . merge-multiple: true - name: Unzip slices shell: bash run: | ls -l . tar -xzv -f build_catalyst_${{ matrix.flavor }}.tar.gz tar -xzv -f build_iphoneos_${{ matrix.flavor }}.tar.gz tar -xzv -f build_iphonesimulator_${{ matrix.flavor }}.tar.gz tar -xzv -f build_appletvos_${{ matrix.flavor }}.tar.gz tar -xzv -f build_appletvsimulator_${{ matrix.flavor }}.tar.gz tar -xzv -f build_macosx_${{ matrix.flavor }}.tar.gz tar -xzv -f build_xros_${{ matrix.flavor }}.tar.gz tar -xzv -f build_xrsimulator_${{ matrix.flavor }}.tar.gz - name: Move back build folders shell: bash run: | ls -l build_* mv build_catalyst_${{ matrix.flavor }} build_catalyst mv build_iphoneos_${{ matrix.flavor }} build_iphoneos mv build_iphonesimulator_${{ matrix.flavor }} build_iphonesimulator mv build_appletvos_${{ matrix.flavor }} build_appletvos mv build_appletvsimulator_${{ matrix.flavor }} build_appletvsimulator mv build_macosx_${{ matrix.flavor }} build_macosx mv build_xros_${{ matrix.flavor }} build_xros mv build_xrsimulator_${{ matrix.flavor }} build_xrsimulator - name: Prepare destroot folder shell: bash run: ./utils/build-apple-framework.sh prepare_dest_root - name: Create universal xcframework shell: bash run: | echo "[HERMES] Creating the universal framework" ./utils/build-apple-framework.sh build_framework chmod +x ./destroot/bin/hermesc - name: Package the Hermes Apple frameworks shell: bash run: | BUILD_TYPE="${{ matrix.flavor }}" echo "Packaging Hermes Apple frameworks for $BUILD_TYPE build type" TARBALL_OUTPUT_DIR=$(mktemp -d /tmp/hermes-tarball-output-XXXXXXXX) echo "Packaging Hermes Apple frameworks for $BUILD_TYPE build type" TARBALL_OUTPUT_PATH=$(node ./utils/scripts/hermes/create-tarball.js \ --inputDir . \ --buildType "$BUILD_TYPE" \ --outputDir $TARBALL_OUTPUT_DIR) echo "Hermes tarball saved to $TARBALL_OUTPUT_PATH" mkdir -p $HERMES_TARBALL_ARTIFACTS_DIR cp $TARBALL_OUTPUT_PATH $HERMES_TARBALL_ARTIFACTS_DIR/. mkdir -p /tmp/hermes/osx-bin/${{ matrix.flavor }} cp ./build_macosx/bin/* /tmp/hermes/osx-bin/${{ matrix.flavor }} ls -lR /tmp/hermes/osx-bin/ - name: Create dSYM archive shell: bash run: | FLAVOR=${{ matrix.flavor }} WORKING_DIR="/tmp/hermes_tmp/dSYM/$FLAVOR" mkdir -p "$WORKING_DIR/macosx" mkdir -p "$WORKING_DIR/catalyst" mkdir -p "$WORKING_DIR/iphoneos" mkdir -p "$WORKING_DIR/iphonesimulator" mkdir -p "$WORKING_DIR/appletvos" mkdir -p "$WORKING_DIR/appletvsimulator" mkdir -p "$WORKING_DIR/xros" mkdir -p "$WORKING_DIR/xrsimulator" DSYM_FILE_PATH=lib/hermesvm.framework.dSYM cp -r build_macosx/$DSYM_FILE_PATH "$WORKING_DIR/macosx/" cp -r build_catalyst/$DSYM_FILE_PATH "$WORKING_DIR/catalyst/" cp -r build_iphoneos/$DSYM_FILE_PATH "$WORKING_DIR/iphoneos/" cp -r build_iphonesimulator/$DSYM_FILE_PATH "$WORKING_DIR/iphonesimulator/" cp -r build_appletvos/$DSYM_FILE_PATH "$WORKING_DIR/appletvos/" cp -r build_appletvsimulator/$DSYM_FILE_PATH "$WORKING_DIR/appletvsimulator/" cp -r build_xros/$DSYM_FILE_PATH "$WORKING_DIR/xros/" cp -r build_xrsimulator/$DSYM_FILE_PATH "$WORKING_DIR/xrsimulator/" DEST_DIR="/tmp/hermes/dSYM/$FLAVOR" tar -C "$WORKING_DIR" -czvf "hermesvm.framework.dSYM" . mkdir -p "$DEST_DIR" mv "hermesvm.framework.dSYM" "$DEST_DIR" - name: Upload hermes dSYM artifacts uses: actions/upload-artifact@v4.3.4 with: name: hermes-dSYM-${{ matrix.flavor }} path: /tmp/hermes/dSYM/${{ matrix.flavor }} - name: Upload hermes Runtime artifacts uses: actions/upload-artifact@v4.3.4 with: name: hermes-darwin-bin-${{ matrix.flavor }} path: /tmp/hermes/hermes-runtime-darwin/hermes-ios-${{ matrix.flavor }}.tar.gz - name: Upload hermes osx artifacts uses: actions/upload-artifact@v4.3.4 with: name: hermes-osx-bin-${{ matrix.flavor }} path: /tmp/hermes/osx-bin/${{ matrix.flavor }} - name: Upload Hermes Artifacts uses: actions/cache/save@v4 if: ${{ github.ref == 'refs/heads/main' || contains(github.ref, '-stable') }} # To avoid that the cache explode. with: key: v4-hermes-artifacts-${{ matrix.flavor }}-${{ matrix.hermes-version }}-${{ matrix.react-native-version }}-${{ hashFiles('./packages/react-native/sdks/hermes-engine/utils/build-apple-framework.sh') }} path: | /tmp/hermes/osx-bin/${{ matrix.flavor }} /tmp/hermes/dSYM/${{ matrix.flavor }} /tmp/hermes/hermes-runtime-darwin/hermes-ios-${{ matrix.flavor }}.tar.gz
What changed
- Add a job timeout so a hung step cannot burn hours of runner time.
What Latchkey heals here
This workflow has steps that commonly fail on transient issues (network, registries, flaky browsers). On Latchkey managed runners they are detected, retried, and self-healed instead of failing your build:
- Dependency installs
This workflow runs 1 job (2 with the matrix expanded) per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.